From 01560cd2852eafa8125fd646619965fa6c9a02e4 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Sun, 29 Dec 2024 18:21:31 +0100 Subject: [PATCH] [FEAT] support native ISO8601 Time serialisation in the tool rest APi and the data need to call the ContextGenericTools.addJsr310(rc); to register it --- pom.xml | 6 +- .../archidata/tools/ContextGenericTools.java | 30 ++++++++ src/org/kar/archidata/tools/RESTApi.java | 9 ++- .../kar/archidata/apiExtern/TestTime.java | 75 +++++++++++++++++++ .../kar/archidata/apiExtern/WebLauncher.java | 5 ++ .../apiExtern/model/DataForJSR310.java | 17 +++++ .../apiExtern/resource/TimeResource.java | 25 +++++++ 7 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 src/org/kar/archidata/tools/ContextGenericTools.java create mode 100644 test/src/test/kar/archidata/apiExtern/TestTime.java create mode 100644 test/src/test/kar/archidata/apiExtern/model/DataForJSR310.java create mode 100644 test/src/test/kar/archidata/apiExtern/resource/TimeResource.java diff --git a/pom.xml b/pom.xml index cde3c80..c11b86c 100644 --- a/pom.xml +++ b/pom.xml @@ -134,18 +134,18 @@ com.fasterxml.jackson.core jackson-databind - 2.18.0-rc1 + 2.18.1 com.fasterxml.jackson.dataformat jackson-dataformat-csv - 2.18.0-rc1 + 2.18.1 com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.18.0-rc1 + 2.18.1 jakarta.servlet diff --git a/src/org/kar/archidata/tools/ContextGenericTools.java b/src/org/kar/archidata/tools/ContextGenericTools.java new file mode 100644 index 0000000..f7d9ceb --- /dev/null +++ b/src/org/kar/archidata/tools/ContextGenericTools.java @@ -0,0 +1,30 @@ +package org.kar.archidata.tools; + +import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import org.glassfish.jersey.server.ResourceConfig; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +public class ContextGenericTools { + + /** + * Add support of Jackson jsr310 for data and time serialization and un-serialization. + * @param rc Resource exception model. + */ + public static void addJsr310(final ResourceConfig rc) { + // Configure Jackson for dates and times + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + // configure jackson provider for JSON mapper + final JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(); + provider.setMapper(objectMapper); + + // Record it on the Resource configuration + rc.register(provider); + + } +} diff --git a/src/org/kar/archidata/tools/RESTApi.java b/src/org/kar/archidata/tools/RESTApi.java index 5bc5617..ab46e48 100644 --- a/src/org/kar/archidata/tools/RESTApi.java +++ b/src/org/kar/archidata/tools/RESTApi.java @@ -17,7 +17,9 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import jakarta.ws.rs.core.HttpHeaders; @@ -25,10 +27,15 @@ public class RESTApi { final static Logger LOGGER = LoggerFactory.getLogger(RESTApi.class); final String baseUrl; private String token = null; - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper; public RESTApi(final String baseUrl) { this.baseUrl = baseUrl; + this.mapper = new ObjectMapper(); + // add by default support of LocalTime and LocalDate and LocalDateTime + this.mapper.registerModule(new JavaTimeModule()); // Module for Java 8+ Date and Time API + this.mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + } public void setToken(final String token) { diff --git a/test/src/test/kar/archidata/apiExtern/TestTime.java b/test/src/test/kar/archidata/apiExtern/TestTime.java new file mode 100644 index 0000000..7f18386 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/TestTime.java @@ -0,0 +1,75 @@ +package test.kar.archidata.apiExtern; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.tools.ConfigBaseVariable; +import org.kar.archidata.tools.RESTApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.kar.archidata.ConfigureDb; +import test.kar.archidata.StepwiseExtension; +import test.kar.archidata.apiExtern.model.DataForJSR310; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestTime { + private final static Logger LOGGER = LoggerFactory.getLogger(TestTime.class); + public final static String ENDPOINT_NAME = "TimeResource"; + + static WebLauncherTest webInterface = null; + static RESTApi api = null; + + private static Long idTest = 0L; + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigureDb.configure(); + LOGGER.info("configure server ..."); + webInterface = new WebLauncherTest(); + LOGGER.info("Clean previous table"); + + LOGGER.info("Start REST (BEGIN)"); + webInterface.process(); + LOGGER.info("Start REST (DONE)"); + api = new RESTApi(ConfigBaseVariable.apiAdress); + api.setToken(Common.ADMIN_TOKEN); + } + + @AfterAll + public static void stopWebServer() throws Exception { + LOGGER.info("Kill the web server"); + webInterface.stop(); + webInterface = null; + ConfigureDb.clear(); + } + + @Order(1) + @Test + public void insertValue() throws Exception { + + final DataForJSR310 data = new DataForJSR310(); + data.time = LocalTime.now(); + data.date = LocalDate.now(); + data.dateTime = LocalDateTime.now(); + + final DataForJSR310 inserted = api.post(DataForJSR310.class, TestTime.ENDPOINT_NAME, data); + Assertions.assertNotNull(inserted); + Assertions.assertNotNull(inserted.time); + Assertions.assertNotNull(inserted.date); + Assertions.assertNotNull(inserted.dateTime); + Assertions.assertEquals(inserted.time, data.time); + Assertions.assertEquals(inserted.date, data.date); + Assertions.assertEquals(inserted.dateTime, data.dateTime); + } +} diff --git a/test/src/test/kar/archidata/apiExtern/WebLauncher.java b/test/src/test/kar/archidata/apiExtern/WebLauncher.java index 1551cea..ec7db65 100755 --- a/test/src/test/kar/archidata/apiExtern/WebLauncher.java +++ b/test/src/test/kar/archidata/apiExtern/WebLauncher.java @@ -22,11 +22,13 @@ import org.kar.archidata.filter.CORSFilter; import org.kar.archidata.filter.OptionFilter; import org.kar.archidata.migration.MigrationEngine; import org.kar.archidata.tools.ConfigBaseVariable; +import org.kar.archidata.tools.ContextGenericTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jakarta.ws.rs.core.UriBuilder; import test.kar.archidata.apiExtern.resource.TestResource; +import test.kar.archidata.apiExtern.resource.TimeResource; public class WebLauncher { final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class); @@ -109,9 +111,12 @@ public class WebLauncher { GenericCatcher.addAll(rc); // add default resource: rc.register(TestResource.class); + rc.register(TimeResource.class); rc.register(DataResource.class); rc.register(ProxyResource.class); + ContextGenericTools.addJsr310(rc); + // add jackson to be discover when we are ins standalone server rc.register(JacksonFeature.class); // enable this to show low level request diff --git a/test/src/test/kar/archidata/apiExtern/model/DataForJSR310.java b/test/src/test/kar/archidata/apiExtern/model/DataForJSR310.java new file mode 100644 index 0000000..ec92dc0 --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/model/DataForJSR310.java @@ -0,0 +1,17 @@ +package test.kar.archidata.apiExtern.model; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +public class DataForJSR310 { + public LocalTime time; + public LocalDate date; + public LocalDateTime dateTime; + + @Override + public String toString() { + return "DataForJSR310 [time=" + this.time + ", date=" + this.date + ", dateTime=" + this.dateTime + "]"; + } + +} diff --git a/test/src/test/kar/archidata/apiExtern/resource/TimeResource.java b/test/src/test/kar/archidata/apiExtern/resource/TimeResource.java new file mode 100644 index 0000000..29d2c3a --- /dev/null +++ b/test/src/test/kar/archidata/apiExtern/resource/TimeResource.java @@ -0,0 +1,25 @@ +package test.kar.archidata.apiExtern.resource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.annotation.security.PermitAll; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import test.kar.archidata.apiExtern.model.DataForJSR310; + +@Path("/TimeResource") +@Produces({ MediaType.APPLICATION_JSON }) +public class TimeResource { + private static final Logger LOGGER = LoggerFactory.getLogger(TimeResource.class); + + @POST + @PermitAll + public DataForJSR310 post(final DataForJSR310 data) throws Exception { + LOGGER.warn("receive Data: {}", data); + return data; + } + +}