Commit 06855370 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Make config of todomodel serialization more flexible.

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