getContext() method of CustomContextResolver is no

2020-04-19 05:44发布

问题:

I am struggling with this issue for days now and have no clue how to solve this. Any quick help will be grateful. I need to convert LocalDate from JSON string which I am receiving from REST service build using apache CXF and jackson. I wrote custom ContextResolver and registered JavaTimeModule in Mapper object. When I run the application, default constructor is called, that means it has been loaded, but getContext() method which returns ObjectMapper never gets called.

I have registered same ContextResolver in server and client side. All dependencies are in place(jackson databind, core, annotation, datatype-jsr310).

I am able to fetch JSON response when I hit REST URI directly in browser. Issue comes when I call same URI annotated method from client code Below is my client code.

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;


@Provider //makes this bean a Provider
public class LocalDateObjectMapperContextResolver implements ContextResolver<ObjectMapper>{

    private final ObjectMapper MAPPER;

    public LocalDateObjectMapperContextResolver() {
        MAPPER = new ObjectMapper();
        MAPPER.registerModule(new JavaTimeModule());
        MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return MAPPER;
    }

}
<jaxrs:client id="testclient"
    serviceClass="package1.RESTService"
    username="abc"
    password="abc"
    address="$serviceURL">

    <jaxrs:features>
        <bean class="org.apache.cxf.transport.common.gzip.GZIPFeature"/>
        <cxf:logging/>
    </jaxrs:features>

    <jaxrs:providers>
        <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
        <bean class="mypackage.LocalDateObjectMapperContextResolver"/>
    </jaxrs:providers>

</jaxrs:client>

Same way, This contextResolver is registered on server side also under

<jaxrs:server>
.....
 <jaxrs:providers>
    <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
            <bean class="mypackage.LocalDateObjectMapperContextResolver"/>
  </jaxrs:providers>
</jaxrs:server>

Any reason why getContext is not called?

I also tried by extending ObjectMapper and registering javaTimeModule there, but dont know how to register customObjectMapper in Jackson flow. I just put default constructor for testing, And it does get called while application startup, but then again, No results, I still get same error.

Error: No suitable constructor found for type [simple type, class java.time.LocalDate]: can not instantiate from JSON object (need to add/enable type information?)

回答1:

I had exactly the same problem @peeskillet describes in question comment.

I was using Jackson dependencies from version 2 and jackson-jaxrs from version 1.

All solved when moved all dependencies to version 2.



回答2:

If you are using Maven you can add following two maven dependency.

        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
        </dependency>

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

And Add following code snippet.

@Configuration
public class CxfConfig {

    @Component
    @javax.ws.rs.ext.Provider
    public static class JacksonJaxbJsonProvider
            extends com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider {

        @Autowired
        private ObjectMapper objectMapper;

        @PostConstruct
        public void init() {

            objectMapper.registerModule(new Jdk8Module());

        }

    }
}