Skip to content
Snippets Groups Projects
Commit 06855370 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Make config of todomodel serialization more flexible.

parent 68e89d60
Branches
No related tags found
No related merge requests found
Showing
with 76 additions and 34 deletions
...@@ -10,6 +10,9 @@ import java.io.Writer; ...@@ -10,6 +10,9 @@ import java.io.Writer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.Set;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.json.internal.TodoModule; import todolist.json.internal.TodoModule;
...@@ -19,19 +22,27 @@ import todolist.json.internal.TodoModule; ...@@ -19,19 +22,27 @@ import todolist.json.internal.TodoModule;
*/ */
public class TodoPersistence { public class TodoPersistence {
public enum TodoModelParts {
SETTINGS, LISTS, LIST_CONTENTS
}
private ObjectMapper mapper; private ObjectMapper mapper;
public TodoPersistence() { public TodoPersistence() {
mapper = createObjectMapper(); mapper = createObjectMapper();
} }
public static SimpleModule createJacksonModule(boolean deep) { public static SimpleModule createJacksonModule(Set<TodoModelParts> parts) {
return new TodoModule(deep); return new TodoModule(parts);
} }
public static ObjectMapper createObjectMapper() { public static ObjectMapper createObjectMapper(Set<TodoModelParts> parts) {
return new ObjectMapper() return new ObjectMapper()
.registerModule(createJacksonModule(true)); .registerModule(createJacksonModule(parts));
}
public static ObjectMapper createObjectMapper() {
return createObjectMapper(EnumSet.allOf(TodoModelParts.class));
} }
public TodoModel readTodoModel(Reader reader) throws IOException { public TodoModel readTodoModel(Reader reader) throws IOException {
......
...@@ -4,19 +4,19 @@ import com.fasterxml.jackson.core.JsonGenerator; ...@@ -4,19 +4,19 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet;
import java.util.Set;
import todolist.core.AbstractTodoList; import todolist.core.AbstractTodoList;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.json.TodoPersistence.TodoModelParts;
class TodoModelSerializer extends JsonSerializer<TodoModel> { class TodoModelSerializer extends JsonSerializer<TodoModel> {
private final boolean deep; private final Set<TodoModelParts> parts;
public TodoModelSerializer(boolean deep) {
this.deep = deep;
}
public TodoModelSerializer() { public TodoModelSerializer(Set<TodoModelParts> parts) {
this(true); this.parts = parts;
} }
/* /*
...@@ -27,11 +27,12 @@ class TodoModelSerializer extends JsonSerializer<TodoModel> { ...@@ -27,11 +27,12 @@ class TodoModelSerializer extends JsonSerializer<TodoModel> {
public void serialize(TodoModel model, JsonGenerator jsonGen, SerializerProvider public void serialize(TodoModel model, JsonGenerator jsonGen, SerializerProvider
serializerProvider) throws IOException { serializerProvider) throws IOException {
jsonGen.writeStartObject(); jsonGen.writeStartObject();
if (parts.contains(TodoModelParts.LIST_CONTENTS) || parts.contains(TodoModelParts.LISTS)) {
jsonGen.writeArrayFieldStart("lists"); jsonGen.writeArrayFieldStart("lists");
for (AbstractTodoList list : model) { for (AbstractTodoList list : model) {
if (deep) { if (parts.contains(TodoModelParts.LIST_CONTENTS)) {
jsonGen.writeObject(list); jsonGen.writeObject(list);
} else { } else if (parts.contains(TodoModelParts.LISTS)) {
jsonGen.writeStartObject(); jsonGen.writeStartObject();
jsonGen.writeStringField("name", list.getName()); jsonGen.writeStringField("name", list.getName());
if (list.getDeadline() != null) { if (list.getDeadline() != null) {
...@@ -42,8 +43,11 @@ class TodoModelSerializer extends JsonSerializer<TodoModel> { ...@@ -42,8 +43,11 @@ class TodoModelSerializer extends JsonSerializer<TodoModel> {
} }
} }
jsonGen.writeEndArray(); jsonGen.writeEndArray();
}
if (parts.contains(TodoModelParts.SETTINGS)) {
jsonGen.writeFieldName("settings"); jsonGen.writeFieldName("settings");
jsonGen.writeObject(model.getSettings()); jsonGen.writeObject(model.getSettings());
}
jsonGen.writeEndObject(); jsonGen.writeEndObject();
} }
} }
\ No newline at end of file
package todolist.json.internal; package todolist.json.internal;
import java.util.EnumSet;
import java.util.Set;
import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import todolist.core.AbstractTodoList; import todolist.core.AbstractTodoList;
import todolist.core.TodoItem; import todolist.core.TodoItem;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.core.TodoSettings; import todolist.core.TodoSettings;
import todolist.json.TodoPersistence.TodoModelParts;
/** /**
* A Jackson module for configuring JSON serialization of TodoModel instances. * A Jackson module for configuring JSON serialization of TodoModel instances.
...@@ -18,7 +22,7 @@ public class TodoModule extends SimpleModule { ...@@ -18,7 +22,7 @@ public class TodoModule extends SimpleModule {
/** /**
* Initializes this TodoModule with appropriate serializers and deserializers. * Initializes this TodoModule with appropriate serializers and deserializers.
*/ */
public TodoModule(boolean deepTodoModelSerializer) { public TodoModule(Set<TodoModelParts> parts) {
super(NAME, Version.unknownVersion()); super(NAME, Version.unknownVersion());
addSerializer(TodoItem.class, new TodoItemSerializer()); addSerializer(TodoItem.class, new TodoItemSerializer());
addDeserializer(TodoItem.class, new TodoItemDeserializer()); addDeserializer(TodoItem.class, new TodoItemDeserializer());
...@@ -26,7 +30,7 @@ public class TodoModule extends SimpleModule { ...@@ -26,7 +30,7 @@ public class TodoModule extends SimpleModule {
addSerializer(AbstractTodoList.class, new TodoListSerializer()); addSerializer(AbstractTodoList.class, new TodoListSerializer());
addDeserializer(AbstractTodoList.class, new TodoListDeserializer()); addDeserializer(AbstractTodoList.class, new TodoListDeserializer());
addSerializer(TodoModel.class, new TodoModelSerializer(deepTodoModelSerializer)); addSerializer(TodoModel.class, new TodoModelSerializer(parts));
addDeserializer(TodoModel.class, new TodoModelDeserializer()); addDeserializer(TodoModel.class, new TodoModelDeserializer());
addSerializer(TodoSettings.class, new TodoSettingsSerializer()); addSerializer(TodoSettings.class, new TodoSettingsSerializer());
...@@ -34,6 +38,6 @@ public class TodoModule extends SimpleModule { ...@@ -34,6 +38,6 @@ public class TodoModule extends SimpleModule {
} }
public TodoModule() { public TodoModule() {
this(true); this(EnumSet.allOf(TodoModelParts.class));
} }
} }
...@@ -3,6 +3,7 @@ package todolist.restapi; ...@@ -3,6 +3,7 @@ package todolist.restapi;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT; import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
...@@ -51,9 +52,11 @@ public class TodoListResource { ...@@ -51,9 +52,11 @@ public class TodoListResource {
this.todoList = todoList; this.todoList = todoList;
} }
// throw an exception in case of missing todolist
// hopefully this will give an appropriate http response code
private void checkTodoList() { private void checkTodoList() {
if (this.todoList == null) { if (this.todoList == null) {
throw new IllegalArgumentException("No TodoList named \"" + name + "\""); throw new NotFoundException("No TodoList named \"" + name + "\"");
} }
} }
...@@ -74,7 +77,7 @@ public class TodoListResource { ...@@ -74,7 +77,7 @@ public class TodoListResource {
try { try {
todoPersistence.saveTodoModel(todoModel); todoPersistence.saveTodoModel(todoModel);
} catch (IllegalStateException | IOException e) { } catch (IllegalStateException | IOException e) {
System.err.println("Couldn't auto-save TodoModel: " + e); LOG.error("Couldn't auto-save TodoModel: ", e);
} }
} }
} }
......
...@@ -8,6 +8,8 @@ import java.nio.charset.StandardCharsets; ...@@ -8,6 +8,8 @@ import java.nio.charset.StandardCharsets;
import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.jackson.JacksonFeature; import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import todolist.core.TodoItem;
import todolist.core.TodoList; import todolist.core.TodoList;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.json.TodoPersistence; import todolist.json.TodoPersistence;
...@@ -71,7 +73,9 @@ public class TodoConfig extends ResourceConfig { ...@@ -71,7 +73,9 @@ public class TodoConfig extends ResourceConfig {
} }
} }
TodoModel todoModel = new TodoModel(); TodoModel todoModel = new TodoModel();
todoModel.addTodoList(new TodoList("todo1")); TodoList todoList1 = new TodoList("todo1");
todoList1.addTodoItem(new TodoItem());
todoModel.addTodoList(todoList1);
todoModel.addTodoList(new TodoList("todo2")); todoModel.addTodoList(new TodoList("todo2"));
return todoModel; return todoModel;
} }
......
package todolist.restserver; package todolist.restserver;
import java.util.EnumSet;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
...@@ -7,6 +9,7 @@ import jakarta.ws.rs.core.MediaType; ...@@ -7,6 +9,7 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.ext.ContextResolver; import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.Provider; import jakarta.ws.rs.ext.Provider;
import todolist.json.TodoPersistence; import todolist.json.TodoPersistence;
import todolist.json.TodoPersistence.TodoModelParts;
/** /**
* Provides the Jackson module used for JSON serialization. * Provides the Jackson module used for JSON serialization.
...@@ -19,7 +22,10 @@ public class TodoModuleObjectMapperProvider implements ContextResolver<ObjectMap ...@@ -19,7 +22,10 @@ public class TodoModuleObjectMapperProvider implements ContextResolver<ObjectMap
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
public TodoModuleObjectMapperProvider() { public TodoModuleObjectMapperProvider() {
objectMapper = TodoPersistence.createObjectMapper(); // Uuse variant which only serializes list properties as part of TodoModel objects, and
// not the contents, nor settings
// The contents or settings are serialized as part of TodoList and TodoSettings objects
objectMapper = TodoPersistence.createObjectMapper(EnumSet.of(TodoModelParts.LISTS));
} }
@Override @Override
......
...@@ -17,6 +17,7 @@ import org.junit.jupiter.api.AfterEach; ...@@ -17,6 +17,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import todolist.core.AbstractTodoList; import todolist.core.AbstractTodoList;
import todolist.core.TodoList;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.restapi.TodoModelService; import todolist.restapi.TodoModelService;
...@@ -84,6 +85,8 @@ public class TodoServiceTest extends JerseyTest { ...@@ -84,6 +85,8 @@ public class TodoServiceTest extends JerseyTest {
try { try {
AbstractTodoList todoList = objectMapper.readValue(getResponse.readEntity(String.class), AbstractTodoList.class); AbstractTodoList todoList = objectMapper.readValue(getResponse.readEntity(String.class), AbstractTodoList.class);
assertEquals("todo1", todoList.getName()); assertEquals("todo1", todoList.getName());
assertTrue(todoList instanceof TodoList);
assertTrue(((TodoList) todoList).iterator().hasNext());
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
fail(e.getMessage()); fail(e.getMessage());
} }
......
package todolist.springboot.restserver; package todolist.springboot.restserver;
import java.util.EnumSet;
import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.Module;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import todolist.json.TodoPersistence; import todolist.json.TodoPersistence;
import todolist.json.TodoPersistence.TodoModelParts;
/** /**
* The Spring application. * The Spring application.
...@@ -14,7 +17,7 @@ public class TodoModelApplication { ...@@ -14,7 +17,7 @@ public class TodoModelApplication {
@Bean @Bean
public Module objectMapperModule() { public Module objectMapperModule() {
return TodoPersistence.createJacksonModule(false); return TodoPersistence.createJacksonModule(EnumSet.of(TodoModelParts.LISTS));
} }
public static void main(String[] args) { public static void main(String[] args) {
......
...@@ -6,6 +6,8 @@ import java.io.Reader; ...@@ -6,6 +6,8 @@ import java.io.Reader;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import todolist.core.TodoItem;
import todolist.core.TodoList; import todolist.core.TodoList;
import todolist.core.TodoModel; import todolist.core.TodoModel;
import todolist.json.TodoPersistence; import todolist.json.TodoPersistence;
...@@ -56,7 +58,9 @@ public class TodoModelService { ...@@ -56,7 +58,9 @@ public class TodoModelService {
} }
} }
TodoModel todoModel = new TodoModel(); TodoModel todoModel = new TodoModel();
todoModel.addTodoList(new TodoList("todo1")); TodoList todoList1 = new TodoList("todo1");
todoList1.addTodoItem(new TodoItem());
todoModel.addTodoList(todoList1);
todoModel.addTodoList(new TodoList("todo2")); todoModel.addTodoList(new TodoList("todo2"));
return todoModel; return todoModel;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment