2

I want to create multiple beans for ObjectMapper, mostly differentiating in date format.

I have written the following code -

@Configuration
public class ObjectMapperConfig {

    @Primary
    @Bean
    public ObjectMapper createDefaultObjectMapper() {
        return new ObjectMapper();
    }

    @Bean(name="AOMapper")
    public ObjectMapper createFacebookObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZ"));
        return objectMapper;
    }

    @Bean(name="BOMapper")
    public ObjectMapper createTwitterObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"));
        return objectMapper;
    }
}

While I am able to use AOMapper and BOMapper using @Qualifier annotation, other third party packages which use just ObjectMapper without the Qualifier annotation are unable to get default ObjectMapper.

Is there a way out?

Update: Following is the exception I get

[com.myorg.service.xyz.client.XyzClient]: Factory method 'getUnstarted' threw exception; nested exception is java.lang.RuntimeException: java.io.UncheckedIOException: Cannot construct instance of `java.time.Instant` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('2018-03-19T22:56:33.339Z')
 at [Source: (ByteArrayInputStream); line: 1, column: 161] (through reference chain: com.myorg.service.xyz.client.WatchResult["updates"]->java.util.ArrayList[0]->com.myorg.service.xyz.client.Announcement["announceTime"]) (code 200)

What I understood from above is that somehow, the XyzClient is not getting the correct default ObjectMapper and therefore unable to deserialize the date format

comiventor
  • 3,922
  • 5
  • 50
  • 77
  • 1
    Could you share an error which third-party packages give? – statut Mar 26 '18 at 13:01
  • those packages are proprietary and am not allowed do any changes. – comiventor Mar 26 '18 at 14:14
  • 2
    but could you share just errors to know an exact cause of the error? I do not ask to do any changes :) – statut Mar 26 '18 at 14:17
  • Can you please share when you do this what is the exception that you get?that will show what are the efforts put by you... – Vinay Prajapati Mar 26 '18 at 19:16
  • doesn't matter you could create n no of beans for same Class type. The only thing is if you are trying to create a bean with same name or trying to qualify the bean for same class type or bean is used by class type... – Vinay Prajapati Mar 26 '18 at 19:17
  • share the error – comiventor Mar 27 '18 at 03:36
  • spring is not the problem here, from the log you can see that the error is caused by serialize/ deserialize java 8 time with jakcson mapper. see this link maybe it helps https://stackoverflow.com/questions/27952472/serialize-deserialize-java-8-java-time-with-jackson-json-mapper?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – SEY_91 Mar 27 '18 at 11:00

2 Answers2

2

The problem is that your ObjectMapper don't know how to deserialize a Instant class, you need to register the jackson module that provides those custom serializers/deserializers. This module is named jackson-datatype-jsr310 and you can import it (when using maven) with this:

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

Then, when you create your object mapper you have to register the JavaTimeModule module.

objectMapper.registerModule(new JavaTimeModule());

So your method should be similar to:

@Bean
@Primary
public ObjectMapper createDefaultObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    return objectMapper;
}
Jose Da Silva Gomes
  • 3,814
  • 3
  • 24
  • 34
0

Could you override the beans of the third party libraries and set the appropriate ObjectMapper. Is it used all over the place in the third party library or in one reusable place? If it is used all over the place, then overriding each bean is likely not feasible. If they use it in a single place, you can probably get away with creating your own @Primary bean to override their defaults.

Also, from the looks of things, it seems like you are sending these 3rd party libraries the date in a given format. Can you not standardize the the format you give these libraries the date?

Mike Baglio Jr.
  • 1,990
  • 3
  • 18
  • 19
  • those packages are proprietary and am not allowed to do any changes. also I have no control over the date input for all the three mappers. The default objectMapper uses its own default format which other packages are also built for. I just wanted to understand if without touching the packages, is it possible to inject create different variants for ObjectMapper. If not, I will be using `ObjectMapper AOMapper = new ObjectMapper();` which is not ideal I believe when all my other application parts are using injected dependencies. – comiventor Mar 26 '18 at 14:18