Commit remaining tracked non-log changes
This commit is contained in:
parent
1128bd3f56
commit
dd9c33c5fd
4
pom.xml
4
pom.xml
|
|
@ -69,6 +69,10 @@
|
|||
<groupId>org.apache.camel.springboot</groupId>
|
||||
<artifactId>camel-jackson-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
|
|
|
|||
|
|
@ -631,6 +631,121 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tachograph composite sessions",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create tachograph composite session",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"sessionIds\": [\n \"{{sessionId}}\",\n \"{{additionalSessionId}}\"\n ],\n \"label\": \"{{compositeSessionLabel}}\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-composite-sessions",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"eventhub",
|
||||
"tachograph-composite-sessions"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get tachograph composite session",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-composite-sessions/{{compositeSessionId}}",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"eventhub",
|
||||
"tachograph-composite-sessions",
|
||||
"{{compositeSessionId}}"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List tachograph composite session drivers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-composite-sessions/{{compositeSessionId}}/drivers",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"eventhub",
|
||||
"tachograph-composite-sessions",
|
||||
"{{compositeSessionId}}",
|
||||
"drivers"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Load tachograph composite driver events",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-composite-sessions/{{compositeSessionId}}/drivers/{{driverKey}}/events",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"eventhub",
|
||||
"tachograph-composite-sessions",
|
||||
"{{compositeSessionId}}",
|
||||
"drivers",
|
||||
"{{driverKey}}",
|
||||
"events"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Load tachograph composite driver timeline",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-composite-sessions/{{compositeSessionId}}/drivers/{{driverKey}}/timeline",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"eventhub",
|
||||
"tachograph-composite-sessions",
|
||||
"{{compositeSessionId}}",
|
||||
"drivers",
|
||||
"{{driverKey}}",
|
||||
"timeline"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
|
|
@ -670,6 +785,18 @@
|
|||
"key": "sessionId",
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
{
|
||||
"key": "additionalSessionId",
|
||||
"value": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
{
|
||||
"key": "compositeSessionId",
|
||||
"value": "00000000-0000-0000-0000-000000000100"
|
||||
},
|
||||
{
|
||||
"key": "compositeSessionLabel",
|
||||
"value": "driver-multi-file sample"
|
||||
},
|
||||
{
|
||||
"key": "driverKey",
|
||||
"value": "12:12345678901200"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package at.procon.eventhub.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
@ -11,7 +13,9 @@ public class JacksonConfig {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean(ObjectMapper.class)
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper().findAndRegisterModules();
|
||||
return new ObjectMapper()
|
||||
.registerModule(new JavaTimeModule())
|
||||
.findAndRegisterModules()
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -442,16 +442,34 @@ public class EventHubEventReadRepository {
|
|||
return Integer.parseInt(value.toString());
|
||||
}
|
||||
|
||||
private JsonNode json(String value) {
|
||||
static JsonNode parseJsonColumn(ObjectMapper objectMapper, String value) {
|
||||
try {
|
||||
return value == null || value.isBlank()
|
||||
JsonNode node = value == null || value.isBlank()
|
||||
? objectMapper.createObjectNode()
|
||||
: objectMapper.readTree(value);
|
||||
while (node != null
|
||||
&& node.isTextual()
|
||||
&& looksLikeEmbeddedJson(node.textValue())) {
|
||||
node = objectMapper.readTree(node.textValue());
|
||||
}
|
||||
return node;
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse JSON column.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonNode json(String value) {
|
||||
return parseJsonColumn(objectMapper, value);
|
||||
}
|
||||
|
||||
private static boolean looksLikeEmbeddedJson(String value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.startsWith("{") || trimmed.startsWith("[");
|
||||
}
|
||||
|
||||
private String syntheticId(String prefix, UUID id) {
|
||||
return id == null ? null : prefix + ":" + id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package at.procon.eventhub.tachographfilesession.api;
|
||||
|
||||
import at.procon.eventhub.tachographfilesession.service.DriverNotFoundInSessionException;
|
||||
import at.procon.eventhub.tachographfilesession.service.DriverNotFoundInCompositeSessionException;
|
||||
import at.procon.eventhub.tachographfilesession.service.LegalRequirementsUploadException;
|
||||
import at.procon.eventhub.tachographfilesession.service.LegalRequirementsXmlDownloadException;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographCompositeSessionNotFoundException;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionNotFoundException;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographXmlValidationException;
|
||||
import at.procon.eventhub.tachographfilesession.service.UnsupportedTachographFileTypeException;
|
||||
|
|
@ -13,12 +15,17 @@ import org.springframework.http.ResponseEntity;
|
|||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice(basePackageClasses = TachographFileSessionController.class)
|
||||
@RestControllerAdvice(basePackageClasses = {
|
||||
TachographFileSessionController.class,
|
||||
TachographCompositeSessionController.class
|
||||
})
|
||||
public class TachographFileSessionExceptionHandler {
|
||||
|
||||
@ExceptionHandler({
|
||||
TachographFileSessionNotFoundException.class,
|
||||
DriverNotFoundInSessionException.class
|
||||
TachographCompositeSessionNotFoundException.class,
|
||||
DriverNotFoundInSessionException.class,
|
||||
DriverNotFoundInCompositeSessionException.class
|
||||
})
|
||||
public ResponseEntity<Map<String, Object>> notFound(RuntimeException exception) {
|
||||
return error(HttpStatus.NOT_FOUND, exception);
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ eventhub:
|
|||
significant-driving-minutes: 3
|
||||
merge-gap-seconds: 0
|
||||
gap-detection-tolerance-seconds: 0
|
||||
timeline-input-mode: events
|
||||
legal-requirements:
|
||||
base-url: ${LEGAL_REQUIREMENTS_BASE_URL:https://legalrequirements.services.bytebar.eu/ODataV4/LR}
|
||||
username: ${LEGAL_REQUIREMENTS_USERNAME:}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,60 @@
|
|||
ID;Name;AlphaCode;NumericCode;DefaultLanguageCode;ID_Certificate;ID_FileLog
|
||||
0;Unknown 0;0;0;NULL;NULL;NULL
|
||||
1;Austria;A;1;de-AT;NULL;NULL
|
||||
2;Albania;AL;2;sq-AL;NULL;NULL
|
||||
3;Andorra;AND;3;ca;NULL;NULL
|
||||
4;Armenia;ARM;4;hy-AM;NULL;NULL
|
||||
5;Azerbaijan;AZ;5;az;NULL;NULL
|
||||
6;Belgium;B;6;NULL;NULL;NULL
|
||||
7;Bulgaria;BG;7;bg-BG;NULL;NULL
|
||||
8;Bosnia Herzegovina;BIH;8;NULL;NULL;NULL
|
||||
9;Belarus;BY;9;be-BY;NULL;NULL
|
||||
10;Switzerland;CH;10;de-CH;NULL;NULL
|
||||
11;Cyprus;CY;11;NULL;NULL;NULL
|
||||
12;Czech Republic;CZ;12;cs-CZ;NULL;NULL
|
||||
13;Germany;D;13;de-DE;NULL;NULL
|
||||
14;Denmark;DK;14;da-DK;NULL;NULL
|
||||
15;Spain;E;15;es-ES;NULL;NULL
|
||||
16;Estonia;EST;16;et-EE;NULL;NULL
|
||||
17;France;F;17;fr-FR;NULL;NULL
|
||||
18;Finland;FIN;18;fi-FI;NULL;NULL
|
||||
19;Liechtenstein;FL;19;de-LI;NULL;NULL
|
||||
20;Faroe Islands;FR;20;fo-FO;NULL;NULL
|
||||
21;United Kingdom;UK;21;en-GB;NULL;NULL
|
||||
22;Georgia;GE;22;ka-GE;NULL;NULL
|
||||
23;Greece;GR;23;el-GR;NULL;NULL
|
||||
24;Hungary;H;24;hu-HU;NULL;NULL
|
||||
25;Croatia;HR;25;hr-HR;NULL;NULL
|
||||
26;Italy;I;26;it-IT;NULL;NULL
|
||||
27;Ireland;IRL;27;en-IE;NULL;NULL
|
||||
28;Iceland;IS;28;is-IS;NULL;NULL
|
||||
29;Kazakhstan;KZ;29;kk-KZ;NULL;NULL
|
||||
30;Luxembourg;L;30;de-LU;NULL;NULL
|
||||
31;Lithuania;LT;31;lt-LT;NULL;NULL
|
||||
32;Latvia;LV;32;lv-LV;NULL;NULL
|
||||
33;Malta;M;33;NULL;NULL;NULL
|
||||
34;Monaco;MC;34;fr-MC;NULL;NULL
|
||||
35;Moldova;MD;35;ro;NULL;NULL
|
||||
36;North Macedonia;MK;36;mk-MK;NULL;NULL
|
||||
37;Norway;N;37;no;NULL;NULL
|
||||
38;Netherlands;NL;38;nl-NL;NULL;NULL
|
||||
39;Portugal;P;39;pt-PT;NULL;NULL
|
||||
40;Poland;PL;40;pl-PL;NULL;NULL
|
||||
41;Romania;RO;41;ro-RO;NULL;NULL
|
||||
42;San Marino;RSM;42;it-IT;NULL;NULL
|
||||
43;Russia;RUS;43;ru-RU;NULL;NULL
|
||||
44;Sweden;S;44;sv-SE;NULL;NULL
|
||||
45;Slovakia;SK;45;sk-SK;NULL;NULL
|
||||
46;Slovenia;SLO;46;sl-SI;NULL;NULL
|
||||
47;Turkmenistan;TM;47;NULL;NULL;NULL
|
||||
48;Turkey;TR;48;tr-TR;NULL;NULL
|
||||
49;Ukraine;UA;49;uk-UA;NULL;NULL
|
||||
50;Vatican City;V;50;it-IT;NULL;NULL
|
||||
51;Yugoslavia;YU;51;NULL;NULL;NULL
|
||||
52;Montenegro;MNE;52;NULL;NULL;763087
|
||||
53;Serbia;SRB;53;NULL;NULL;272576
|
||||
54;Uzbekistan;UZ;54;NULL;NULL;308001
|
||||
55;Tajikistan;TJ;55;NULL;NULL;NULL
|
||||
253;European Community;EC;253;NULL;NULL;NULL
|
||||
254;Rest of Europe;EUR;254;NULL;NULL;NULL
|
||||
255;Rest of the world;WLD;255;NULL;NULL;NULL
|
||||
ID;Name;AlphaCode;NumericCode
|
||||
0;Unknown 0;0;0
|
||||
1;Austria;A;1
|
||||
2;Albania;AL;2
|
||||
3;Andorra;AND;3
|
||||
4;Armenia;ARM;4
|
||||
5;Azerbaijan;AZ;5
|
||||
6;Belgium;B;6
|
||||
7;Bulgaria;BG;7
|
||||
8;Bosnia Herzegovina;BIH;8
|
||||
9;Belarus;BY;9
|
||||
10;Switzerland;CH;10
|
||||
11;Cyprus;CY;11
|
||||
12;Czech Republic;CZ;12
|
||||
13;Germany;D;13
|
||||
14;Denmark;DK;14
|
||||
15;Spain;E;15
|
||||
16;Estonia;EST;16
|
||||
17;France;F;17
|
||||
18;Finland;FIN;18
|
||||
19;Liechtenstein;FL;19
|
||||
20;Faroe Islands;FR;20
|
||||
21;United Kingdom;UK;21
|
||||
22;Georgia;GE;22
|
||||
23;Greece;GR;23
|
||||
24;Hungary;H;24
|
||||
25;Croatia;HR;25
|
||||
26;Italy;I;26
|
||||
27;Ireland;IRL;27
|
||||
28;Iceland;IS;28
|
||||
29;Kazakhstan;KZ;29
|
||||
30;Luxembourg;L;30
|
||||
31;Lithuania;LT;31
|
||||
32;Latvia;LV;32
|
||||
33;Malta;M;33
|
||||
34;Monaco;MC;34
|
||||
35;Moldova;MD;35
|
||||
36;North Macedonia;MK;36
|
||||
37;Norway;N;37
|
||||
38;Netherlands;NL;38
|
||||
39;Portugal;P;39
|
||||
40;Poland;PL;40
|
||||
41;Romania;RO;41
|
||||
42;San Marino;RSM;42
|
||||
43;Russia;RUS;43
|
||||
44;Sweden;S;44
|
||||
45;Slovakia;SK;45
|
||||
46;Slovenia;SLO;46
|
||||
47;Turkmenistan;TM;47
|
||||
48;Turkey;TR;48
|
||||
49;Ukraine;UA;49
|
||||
50;Vatican City;V;50
|
||||
51;Yugoslavia;YU;51
|
||||
52;Montenegro;MNE;52
|
||||
53;Serbia;SRB;53
|
||||
54;Uzbekistan;UZ;54
|
||||
55;Tajikistan;TJ;55
|
||||
253;European Community;EC;253
|
||||
254;Rest of Europe;EUR;254
|
||||
255;Rest of the world;WLD;255
|
||||
|
|
|
|||
|
|
|
@ -6,6 +6,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import at.procon.eventhub.dto.EventDetailsDto;
|
||||
import at.procon.eventhub.dto.DriverRefDto;
|
||||
import at.procon.eventhub.dto.EventDomain;
|
||||
import at.procon.eventhub.dto.EventHubEventDto;
|
||||
|
|
@ -23,21 +24,32 @@ import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService;
|
|||
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
class UnifiedRuntimeProcessingControllerTest {
|
||||
|
||||
private final ObjectMapper objectMapper = testObjectMapper();
|
||||
|
||||
@Test
|
||||
void loadsDriverEventsViaRuntimeApi() throws Exception {
|
||||
UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class);
|
||||
UnifiedRuntimeDriverTimelineService timelineService = org.mockito.Mockito.mock(UnifiedRuntimeDriverTimelineService.class);
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new UnifiedRuntimeProcessingController(eventAssemblyService, timelineService))
|
||||
.setMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
|
||||
.setControllerAdvice(new UnifiedRuntimeProcessingExceptionHandler())
|
||||
.build();
|
||||
|
||||
|
|
@ -77,7 +89,9 @@ class UnifiedRuntimeProcessingControllerTest {
|
|||
.andExpect(jsonPath("$.request.sessionId").value(sessionId.toString()))
|
||||
.andExpect(jsonPath("$.request.driverKey").value("12:123"))
|
||||
.andExpect(jsonPath("$.discoveredVehicles[0].vin").value("VIN-1"))
|
||||
.andExpect(jsonPath("$.mergedEvents[0].externalSourceEventId").value("EV-1"));
|
||||
.andExpect(jsonPath("$.mergedEvents[0].externalSourceEventId").value("EV-1"))
|
||||
.andExpect(jsonPath("$.mergedEvents[0].payload.raw.driverKey").value("12:123"))
|
||||
.andExpect(jsonPath("$.mergedEvents[0].eventDetails.attributes.cardSlot").value("DRIVER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -85,6 +99,7 @@ class UnifiedRuntimeProcessingControllerTest {
|
|||
UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class);
|
||||
UnifiedRuntimeDriverTimelineService timelineService = org.mockito.Mockito.mock(UnifiedRuntimeDriverTimelineService.class);
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new UnifiedRuntimeProcessingController(eventAssemblyService, timelineService))
|
||||
.setMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
|
||||
.setControllerAdvice(new UnifiedRuntimeProcessingExceptionHandler())
|
||||
.build();
|
||||
|
||||
|
|
@ -152,6 +167,7 @@ class UnifiedRuntimeProcessingControllerTest {
|
|||
UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class);
|
||||
UnifiedRuntimeDriverTimelineService timelineService = org.mockito.Mockito.mock(UnifiedRuntimeDriverTimelineService.class);
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new UnifiedRuntimeProcessingController(eventAssemblyService, timelineService))
|
||||
.setMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
|
||||
.setControllerAdvice(new UnifiedRuntimeProcessingExceptionHandler())
|
||||
.build();
|
||||
|
||||
|
|
@ -182,11 +198,31 @@ class UnifiedRuntimeProcessingControllerTest {
|
|||
EventLifecycle.START,
|
||||
null,
|
||||
null,
|
||||
new EventDetailsDto("DRIVER_ACTIVITY", objectMapper.valueToTree(Map.of("cardSlot", "DRIVER"))),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
objectMapper.valueToTree(Map.of("raw", Map.of("driverKey", "12:123", "intervalId", "ACT-1"))),
|
||||
false,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private ObjectMapper testObjectMapper() {
|
||||
SimpleModule module = new SimpleModule();
|
||||
module.addSerializer(OffsetDateTime.class, new StdScalarSerializer<>(OffsetDateTime.class) {
|
||||
@Override
|
||||
public void serialize(OffsetDateTime value, JsonGenerator gen, com.fasterxml.jackson.databind.SerializerProvider provider)
|
||||
throws java.io.IOException {
|
||||
gen.writeString(value == null ? null : value.toString());
|
||||
}
|
||||
});
|
||||
module.addDeserializer(OffsetDateTime.class, new StdScalarDeserializer<>(OffsetDateTime.class) {
|
||||
@Override
|
||||
public OffsetDateTime deserialize(JsonParser p, com.fasterxml.jackson.databind.DeserializationContext ctxt)
|
||||
throws java.io.IOException {
|
||||
String value = p.getValueAsString();
|
||||
return value == null || value.isBlank() ? null : OffsetDateTime.parse(value);
|
||||
}
|
||||
});
|
||||
return new ObjectMapper().registerModule(module);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue