2

I am testing my spring-boot code for Controller. for that I have written test like below

@RunWith(SpringRunner.class)
@WebMvcTest(AnimalController.class)
class AnimalControllerTest {

    @Autowired
    MockMvc mvc;
    @MockBean
    AnimalService animalService;

 

    @Test
    void addAnimal() throws Exception {
        AnimalDto animalDto = new AnimalDto();
        mvc.perform(MockMvcRequestBuilders
                   .post("/animal/add")
                   .content(asJsonString(new AnimalDto(null, "dog", LocalDateTime.now(),null, null, null, null)))
                   .contentType(MediaType.APPLICATION_JSON)
                   .accept(MediaType.APPLICATION_JSON))
                   .andExpect(status().isOk())
                   .andDo(MockMvcResultHandlers.print())
                   .andExpect(MockMvcResultMatchers.jsonPath("$.id").exists());

    }
}
 private String asJsonString(Object animalDto) {
        try {
            return new ObjectMapper().writeValueAsString(animalDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

but I am getting below error

java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.self.zoo.dto.AnimalDto["located"])

    at com.self.zoo.controller.AnimalControllerTest.asJsonString(AnimalControllerTest.java:63)
    at com.self.zoo.controller.AnimalControllerTest.addAnimal(AnimalControllerTest.java:50)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)


Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.self.zoo.dto.AnimalDto["located"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)

but I see in my classpath I see both JSR-310 jar as well Java faster-json-Java8 jar as well. enter image description here add below are there maven dependency:

    <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>
<dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-modules-java8</artifactId>
            <version>2.13.3</version>
            <type>pom</type>
            <scope>runtime</scope>
        </dependency>
LowCool
  • 1,187
  • 5
  • 25
  • 51
  • Remoe the version, type and scope from the `jackson-modules-java8` dependency. I even believe you can remove both dependencies as those are automatically included. Finally what does your `asJsonString` method look like, as that is the culprit and you left out the implementation. – M. Deinum May 23 '22 at 18:07
  • Hi @M.Deinum added missing pieces – LowCool May 23 '22 at 18:19
  • Don't do `new ObjectMapper`. Inject the `ObjectMapper` (Spring Boot creates one) and use that. – M. Deinum May 24 '22 at 05:49
  • @M.Deinum can you please add this as ur answer and how to do that? – LowCool May 24 '22 at 06:26

3 Answers3

3

In your code you are using a newly instantiated ObjectMapper which doesn't have all the modules registered. Instead use the pre-configured ObjectMapper provided by Spring Boot. You can @Autowired this into your test to use it.


@Autowired
private ObjectMapper mapper;

private String asJsonString(Object animalDto) {
  try {
    return mapper.writeValueAsString(animalDto); 
  } catch (JsonProcessingException e) {
    throw new RuntimeException(e); 
  }
}

In your dependencies you don't need to add the jackson-datatype-jsr310 and jackson-modules-java8. Those are already, by default, provided by Spring Boot and automatically configured. So remove those dependencies.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
-1

You need to register JavaTimeModule explicitly with ObjectMapper instance.

@Bean
public ObjectMapper mapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    return mapper;
}

You can refer https://github.com/FasterXML/jackson-modules-java8#usage

Yuvaraj R
  • 107
  • 1
  • 5
  • 1
    He is using Spring so no he doesn't need to do that. – M. Deinum May 23 '22 at 18:06
  • @M.Deinum Isn't the exception clearly states that the date time module is not supported by default? and we need to explicitly add it to the mapper? – Yuvaraj R May 23 '22 at 18:40
  • 1
    It is statihg that and where am I disputing that. I'm merely stating that when using Spring Boot you don't need this as it will detect that module and register it automatically. In fact this configuration will break registration of other well known modules and disable parts of the Spring Boot auto-configuration. – M. Deinum May 24 '22 at 05:48
-2

Annotate your property with annotation

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")

Here is the question with full answer that explains it all: Spring Data JPA - ZonedDateTime format for json serialization

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36