spring-boot: Spring Boot 2.5.0 and InvalidDefinitionException: Java 8 date/time type `java.time.Instant` not supported by default

After update from Spring Boot 2.4.5 to Spring 2.5.0 I noticed the following exceptions in the application logs:

Caused by: 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 (through reference chain: org.telegram.telegrambots.meta.api.objects.Update["my_chat_member"]->org.telegram.telegrambots.meta.api.objects.ChatMemberUpdated["new_chat_member"]->org.telegram.telegrambots.meta.api.objects.ChatMember["untilDateAsInstant"])
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1514) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1215) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1059) ~[jackson-databind-2.12.3.jar!/:2.12.3]
	at org.springframework.jms.support.converter.MappingJackson2MessageConverter.mapToTextMessage(MappingJackson2MessageConverter.java:279) ~[spring-jms-5.3.7.jar!/:5.3.7]
	at org.springframework.jms.support.converter.MappingJackson2MessageConverter.toMessage(MappingJackson2MessageConverter.java:184) ~[spring-jms-5.3.7.jar!/:5.3.7]
	... 37 common frames omitted

this is my pom.xml:

	<dependency>
		<groupId>com.fasterxml.jackson.datatype</groupId>
		<artifactId>jackson-datatype-jsr310</artifactId>
	</dependency>

	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-core</artifactId>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-annotations</artifactId>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
	</dependency>

I reverted to Spring Boot 2.4.5 and not everything works fine. What may be wrong with Spring Boot 2.5.0 ?

UPDATED

The same issue exists in Spring Boot 2.5.1

Corresponding question on StackOverflow https://stackoverflow.com/questions/67874510/spring-boot-2-5-0-and-invaliddefinitionexception-java-8-date-time-type-java-ti

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 52 (16 by maintainers)

Most upvoted comments

According to explained beaver 2.4.5 should fail as well

No it shouldn’t. Please see this earlier comment for details of how Jackson 2.11 behaves. Note that serialization to JSON doesn’t fail but it isn’t in the expected format.

@DataJpaTest doesn’t include any Jackson-related auto-configuration. If you want to use the auto-configured ObjectMapper in a Data JPA test, you should import the auto-configuration:

@ImportAutoConfiguration(JacksonAutoConfiguration.class)

If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

Thanks for the sample. Spring Boot upgraded to Jackson 2.12 which contains this change. As a result, if an attempt is made to serialise a java.time.* type and the com.fasterxml.jackson.datatype:jackson-datatype-jsr310 module isn’t on the classpath, it will now fail with an error message rather than limping along and serialising to something unexpected. The same problem occurs with Spring Boot 2.4.x if you use ext['jackson.version'] = '2.12.3' in your build.gradle to upgrade to Jackson 2.12.

I confirm this issue. I think 2.5.x does show up this issue out of different issues. I think the common thing i see is, that other libraries also including js310, use 2.11 and not 2.12. Candidates

So when using springfox < 3.0.0 (which just has been released) people run into the same issue (https://github.com/spring-projects/spring-boot/issues/26685) Same goes with session-mongo (for me).

So i assume not all projects run into this issue, only those, who use other dependencies which include an < 2.12 jackson jsr303 wich then is not compatible during runtime and cannot be used. the reason is, that scanning the classpath for the right one can lead to the first, older one.

You can check the ones you have in your classpath by running

./gradlew dependencyInsight --dependency=jsr310

If you define your own ObjectMapper it is to be expected that this will switch off Spring Boot’s Jackson auto-configuration. This is to allow an application to take complete control of Jackson’s configuration. Spring Boot will use the user-defined defined ObjectMapper as-is.

Nothing should have changed in this area in Spring Boot 2.5. If someone can provide a minimal sample application that works with 2.4.x and then fails after upgrading to 2.5.x, we will happily take a look.

It wasn’t a well known open source library but a custom library created by another internal group. It’s kind of hard to debug as Configuration magic can happen in many places.

@7-- I create a new project using Spring Boot 2.6.2 from start.spring.io and added the following code:

@SpringBootApplication
public class DemoApplication {

	@Bean
	@Primary
	public ObjectMapper primaryObjectMapper() {
		return JsonMapper.builder().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
				.addModule(new JavaTimeModule()).build();
	}

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

With an application.properties of:

management.endpoints.web.exposure.include=*
management.endpoint.info.enabled=true
info.test=hello

I don’t get any failure so there must be something else going on with your application. Please can you provide a sample that shows the problem you’re facing.

The dependecy I’m using updated thier ObjectMapper so I don’t think I’ll have the issue anymore, but thank you for posting I’ll try again if I see the error again.

@7-- I create a new project using Spring Boot 2.6.2 from start.spring.io and added the following code:

@SpringBootApplication
public class DemoApplication {

	@Bean
	@Primary
	public ObjectMapper primaryObjectMapper() {
		return JsonMapper.builder().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
				.addModule(new JavaTimeModule()).build();
	}

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

With an application.properties of:

management.endpoints.web.exposure.include=*
management.endpoint.info.enabled=true
info.test=hello

I don’t get any failure so there must be something else going on with your application. Please can you provide a sample that shows the problem you’re facing.

It seems that the problem was related to SNS Autoconfiguration creating a default MappingJackson2MessageConverter that does not take into account the global ObjectMapper

Thanks for letting us know. As described in previous comments, the problem can be caused by anything that results in an ObjectMapper being used that doesn’t have the JSR-310 module registered. A MappingJackson2MessageConverter that doesn’t use the auto-configured ObjectMapper is one such cause.

My code creates a lot of ObjectMappers but what does that have to do with the /info endpoint?

If one of those ObjectMapper instances that you create is defined as a @Bean, it will be used by all of the Actuator’s endpoints to serialize their responses to json. We may move to a separate Actuator-specific ObjectMapper in the future, but this is the way things work at the moment.

How could I fix that from my side

Ensure that your ObjectMapper @Bean (or the one that is @Primary if you have defined more than one) has the JSR-310 module registered.

@eranf91 You are using @Import in your test in the same way that @EugenMayer was above. As I’ve already explained, this results in the auto-configured ObjectMapper being replaced by an ObjectMapper in its default configuration.

I understand now it is not working. but that’s raise the question why in version 2.4.5 it works and version 2.5.0 not working. According to explained beaver 2.4.5 should fail as well

@wilkinsona You are right, I did not produce the defect correctly. In the example I provided a web mvc test that used the auto configured object mapper to parse the object and this is working as expected.

but in my case I have a service: ‘simpleService’ with auto configured object mapper in service: ‘simpleService’ I have a method get, the method is using the object mapper to convert a object to hash map. I also have a DataJpaTest the test is auto-wiring the simple service and call the get method.

I have fixed the example to reproduce the issue as explained above.

springboot-isseus.tar.gz

@eranf91 You are creating the ObjectMapper instance yourself in your test which means it is in its default configuration and does not have the JSR-310 module registered. As describe above, this fails with Jackson 2.12 due to this change in Jackson. Rather than creating your own ObjectMapper, you can use the auto-configured instance by injecting it into your test:

@WebMvcTest(controllers = {SimpleController.class})
class SimpleControllerTest {
    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @SneakyThrows
    @Test
    void test(){
        mockMvc.perform(post("/simple")
                .contentType(APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(SimpleRequest.builder()
                        .time(now())
                        .build())))
                .andExpect(status().isOk());
    }
}

FWIW, your jackson-no-issue test is quite different to the jackson-issue test as it isn’t serialising a SimpleRequest instance:

@WebMvcTest(controllers = {SimpleController.class})
@FieldDefaults(level = PRIVATE)
@Slf4j
class SimpleControllerTest {
    @Autowired
    MockMvc mockMvc;

    @SneakyThrows
    @Test
    void test() {
        ObjectMapper objectMapper = new ObjectMapper();
        String body = objectMapper.writeValueAsString(Map.of("time", now().toEpochSecond()));
        log.info("Send: {}", body);
        mockMvc.perform(post("/simple")
                .contentType(APPLICATION_JSON)
                .content(body))
                .andExpect(status().isOk());
    }

}

Due to this, it works with either Jackson 2.11 (Spring Boot 2.4) or Jackson 2.12 (Spring Boot 2.5).

The issue does not relate to the import annotation. I am attaching a tar file contains a project with 2 modules, the only different is the springboot version. each module contains a webmvc test

  1. springboot version2.5.2.
  2. springboot version 2.4.5

  1. mvn clean install -> failure
  2. mvn clean install success

springboot-isseus.tar.gz

Update: I found the root cause for my issue regarding the actuator/info endpoint. 😃 Apparently, there was a place in the code generating a new ObjectMapper bean, and overriding the default. In this case, the ObjectMapper did not load jsr310 and additional java.time classes converters such as Instant. There are 2 ways to fix:

  1. Remove the custom ObjectMapper bean overriding the springboot default.
  2. Configure the custom bean: objectMapper.registerModule(new JavaTimeModule());

thanks @wilkinsona . I debugged my application, and I do see the module com.fasterxml.jackson.datatype.jsr310.JavaTimeModule loaded in the registerWellKnownModulesIfAvailable method you sent. However, I still get the same error for the /actuator/info endpoint. On the other hand, I noticed that another application I have and also upgraded to 2.5.1 doesn’t have this issue… Unfortunately, I cannot tell at this point what is the difference between the two apps and what the root cause is. It will require additional investigation.