Reputation: 21496
I'm using RESTEasy 3.1.0.CR3 with Tomcat 8.5.6 inside Eclipse 4.6.1, with the JSBoss resteasy-jackson2-provider. I have a simple JavaBean FooBar
that returns a string "ID" and a java.nio.file.Path
"path".
Jackson makes this easy to serialize to JSON. In my JAX-RS resource I simply specify @Produces("application/json; charset=UTF-8")
. But Jackson is not using Path.toString()
. Instead it appears to be using Path.toURI().toString()
or something:
{
"id": "foo",
"path": "file:///C:/Users/jdoe/bar"
}
Why!?? And more importantly, how can I get Jackson to simply use the toString()
version of Path
?
Here is my project dependency tree:
+- com.google.code.findbugs:jsr305:jar:3.0.1:provided
+- com.google.guava:guava:jar:20.0:compile
+- javax.ws.rs:javax.ws.rs-api:jar:2.0.1:provided
+- org.jboss.resteasy:resteasy-jaxrs:jar:3.1.0.CR3:compile
| +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.0_spec:jar:1.0.1.Beta1:compile
| +- org.jboss.resteasy:resteasy-jaxrs-services:jar:3.1.0.CR3:compile
| +- org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:jar:1.0.0.Final:compile
| +- javax.activation:activation:jar:1.1.1:compile
| +- org.apache.httpcomponents:httpclient:jar:4.5.2:compile
| | +- org.apache.httpcomponents:httpcore:jar:4.4.4:compile
| | +- commons-logging:commons-logging:jar:1.2:compile
| | \- commons-codec:commons-codec:jar:1.9:compile
| +- commons-io:commons-io:jar:2.5:compile
| +- net.jcip:jcip-annotations:jar:1.0:compile
| \- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
+- org.jboss.resteasy:resteasy-servlet-initializer:jar:3.1.0.CR3:compile
+- org.jboss.resteasy:resteasy-jackson2-provider:jar:3.1.0.CR3:compile
| +- com.fasterxml.jackson.core:jackson-core:jar:2.8.3:compile
| +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.3:compile
| +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.3:compile
| \- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.8.3:compile
| +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.8.3:compile
| \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.8.3:compile
+- junit:junit:jar:4.12:test
| \- org.hamcrest:hamcrest-core:jar:1.3:test
\- org.hamcrest:hamcrest-library:jar:1.3:test
Note that it is not acceptable for me to add annotations to my FooBar
class, which is a domain model class that should have no coupling with the RESTful API serialization details.
I want a simple way to hook into Jackson2 in RESTEasy and modify the serialization of a Path
property value without modifying my class or writing a custom serializer for my class.
Upvotes: 4
Views: 2415
Reputation: 416
This class will override default Jackson2JsonProvider help you to configure ObjectMapper, according to you needs, like serializer for Path.class is overriden to ToStringSerializer from NioPathSerializer.
@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CustomJacksonProvider extends JacksonJsonProvider {
public CustomJacksonProvider(){
super(configureMapper(new ObjectMapper()));
}
public static ObjectMapper configureMapper(ObjectMapper mapper) {
SimpleModule m = new SimpleModule("PathToString");
m.addSerializer(Path.class,new ToStringSerializer());
mapper.registerModule(m);
return mapper;
}
}
Or you can use ContextResolver also for the same which will use ResteasyJackson2Provider(RestEasy default)
@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CustomJacksonProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper mapper;
public CustomJacksonProvider(){
mapper = new JsonMapperConfigurator(new ObjectMapper(), JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS)
.getConfiguredMapper();
SimpleModule m = new SimpleModule("PathToString");
m.addSerializer(Path.class, new ToStringSerializer());
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Add this to you web.xml
irrespective of approch you use:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>package.to.CustomJacksonProvider</param-value>
</context-param>
If you are not using a web.xml
file, return the provider class in your JAX-RS application's Application.getClasses()
method.
Hope this helps.
Edited:
Also, you might miss JAXB annotation support in this implementation you have to configure that manually, because JacksonJaxbJsonProvider
doesn't look for Resolver/provider of JsonMapperConfigurator
. Use JsonMapperConfiguration
with mapper in CustomJackosnProvider
along with JacksonJaxbJsonProvider.DEAFULT_ANNOATIONS
. Ideally, since there is no provision to provide JsonMapperConfiguration
Resolver/Provider and RestEasy's jackson provider doesn't expose arg constructor, provider is best bet. Since they taken this decision, ideally they should not do any customization in ResteasyJackson2Provider
. Also, only functionality in ResteasyJackson2Provider
is custom json type and better caching of mapper at class level.
Updated code according to explanation
Upvotes: 4