Spring Boot 2.7.6: Java 8 date/time type `java.time.Instant` not supported by default
I know there have been a few duplicates of my question but none have resolved my issue so I'm creating a new question.
I have a spring boot app (v 2.7.6) with JDK17 which queries an ElasticSearch object. This object contains an Instant field which when being mapped to an Java object is causing the following error:
2022-12-07 00:43:14.442 ERROR 59384 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/api/v1] threw exception [Request processing failed; nested exception is co.elastic.clients.json.JsonpMappingException: Error deserializing co.elastic.clients.elasticsearch.core.GetResponse: jakarta.json.JsonException: Jackson exception (JSON path: _source) (line no=1, column no=280, offset=-1)] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.Instant` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
at [Source: (org.apache.http.nio.entity.ContentInputStream); line: 1, column: 279] (through reference chain: test.com.model.Project["createdDate"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1909) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.impl.UnsupportedTypeDeserializer.deserialize(UnsupportedTypeDeserializer.java:48) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4706) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2879) ~[jackson-databind-2.14.1.jar:2.14.1]
at co.elastic.clients.json.jackson.JacksonJsonpMapper$JacksonValueParser.deserialize(JacksonJsonpMapper.java:123) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.JsonpDeserializer.deserialize(JsonpDeserializer.java:76) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.JsonpMapperBase.deserialize(JsonpMapperBase.java:70) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.JsonpDeserializer$1.deserialize(JsonpDeserializer.java:99) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.NamedDeserializer.deserialize(NamedDeserializer.java:64) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.ObjectDeserializer$FieldObjectDeserializer.deserialize(ObjectDeserializer.java:78) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.ObjectDeserializer.deserialize(ObjectDeserializer.java:192) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.ObjectDeserializer.deserialize(ObjectDeserializer.java:148) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.JsonpDeserializer.deserialize(JsonpDeserializer.java:76) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.ObjectBuilderDeserializer.deserialize(ObjectBuilderDeserializer.java:79) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.DelegatingDeserializer$SameType.deserialize(DelegatingDeserializer.java:43) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.json.DelegatingDeserializer$SameType.deserialize(DelegatingDeserializer.java:43) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.transport.endpoints.EndpointWithResponseMapperAttr$1.deserialize(EndpointWithResponseMapperAttr.java:56) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.transport.rest_client.RestClientTransport.decodeResponse(RestClientTransport.java:325) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.transport.rest_client.RestClientTransport.getHighLevelResponse(RestClientTransport.java:295) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.transport.rest_client.RestClientTransport.performRequest(RestClientTransport.java:148) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.elasticsearch.ElasticsearchClient.get(ElasticsearchClient.java:831) ~[elasticsearch-java-8.5.1.jar:na]
at co.elastic.clients.elasticsearch.ElasticsearchClient.get(ElasticsearchClient.java:847) ~[elasticsearch-java-8.5.1.jar:na]
...
.....
Originally I had no JacksonConfiguration so I would have thought the default jackson would have just worked.
After reading other stackoverflow posts I have tried creating a configuration class like so, but it has not resolved the issue:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.openapitools.jackson.nullable.JsonNullableModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class JacksonConfiguration {
private final ObjectMapper objectMapper;
public JacksonConfiguration(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Bean
public JavaTimeModule dateTimeModule(){
return new JavaTimeModule();
}
@PostConstruct
ObjectMapper jacksonObjectMapper() {
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new JsonNullableModule());
return objectMapper;
}
}
Here are also my dependancies:
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb'
implementation group: 'org.springframework.data', name: 'spring-data-elasticsearch', version: '5.0.0'
implementation 'org.elasticsearch.client:elasticsearch-rest-client:8.5.2'
implementation 'co.elastic.clients:elasticsearch-java:8.5.1'
implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client:7.17.6'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security'
implementation group: 'org.springframework.security', name: 'spring-security-oauth2-client'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server'
// implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.13'
implementation 'org.springdoc:springdoc-openapi-security:1.6.13'
implementation 'org.springdoc:springdoc-openapi-webmvc-core:1.6.13'
implementation 'org.springdoc:springdoc-openapi-webflux-core:1.6.13'
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.6.13'
implementation("org.springframework.cloud:spring-cloud-gcp-starter-pubsub:1.2.8.RELEASE")
implementation("org.springframework.integration:spring-integration-core")
implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-logging'
implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-logging', version: '1.2.8.RELEASE'
implementation group: 'co.elastic.logging', name: 'logback-ecs-encoder', version: '1.3.2'
implementation group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.12.142'
implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
// implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.13.1'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.14.1'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
implementation group: 'org.json', name: 'json', version: '20201115'
implementation group: 'org.openapitools', name: 'jackson-databind-nullable', version: '0.2.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.1'
implementation 'jakarta.json:jakarta.json-api:2.0.1'
implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
implementation 'commons-io:commons-io:2.11.0'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'com.google.guava:guava:31.0.1-jre'
implementation group: 'com.auth0', name: 'java-jwt', version: '3.12.0'
implementation group: 'com.auth0', name: 'auth0', version: '1.34.1'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
implementation group: 'commons-codec', name: 'commons-codec', version: '1.15'
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 开发者_C百科'org.projectlombok:lombok:1.18.22'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
testImplementation 'org.projectlombok:lombok:1.18.20'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}
Two things, add the dependency the error log talks about (which I see you did) and then create a objectmapper bean in your spring configs for your service to use. Please remove what you have in the config class above and simply it to just this one bean method:
@Bean
ObjectMapper jacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
精彩评论