Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customize Json serializer instead of Jersey's default?

I am using Jersey to implement RESTful webservice. Now the MediaType in which I return data is JSON.

@GET
@Produces({MediaType.APPLICATION_JSON })
public Response service() {
    return Response
            .ok(entity)
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
            .build();
}

Here I set CONTENT_TYPE to json and my entity will be converted to json by Jersey framework.

Now I want to customize my json response.

Eg: I want to remove the empty elements or change the keys name of my Json object. Default Jersey's Json conversion:

{
   "cinter" : {
     "state" : 1,
     "checks" : 10,
   }
}

What I want:

{
   "cin" : {
     "st" : 1,
     "cs" : 10,
   }
}

I know I can use Jackson library's my own ObjectMapper to customize my Json according to my needs.

But is this the standard way to do it if I want JSON conversion in a different way than Jersey's default conversion ??

Or can I change paramaters in Jersey's ObjectMapper ??

Should I be using my own ObjectMapper ?

like image 788
Siddharth Trikha Avatar asked May 20 '16 06:05

Siddharth Trikha


1 Answers

Here is my thoughts about your options. First of all

So for every different response I should configure ObjectMapper differently ?

If you want to use both json versions in different places like this

public Response getObject()           // returns {"cinter" : {"state" : 1,"checks" : 10}}
public Response getShortNamesObject() // returns {"cin" : {"st" : 1,"cs" : 10}}

Than yep, you have to use multiple ObjectMappers.

But if you just want to use 1 representation everywhere, then you probably will be able to setup Jackson once with custom mixin for you classes. Anyway here is how you can do both options: And lets look at simple case with just 1 json version needed

public class TestBean {
    private String name;
    private int id;
    //getters and setters
}

public interface TestBeanMixin {
    @JsonProperty("short_field_name")
    String getName();
    @JsonProperty("short_field_id")
    int getId();
}

@Provider
@Priority(1)
public class MixInJacksonJsonProvider extends JacksonJaxbJsonProvider {
    private static final ObjectMapper mapper = createMapper();

    public MixInJacksonJsonProvider() {
        setMapper(mapper);
    }

    private static ObjectMapper createMapper() {
        final ObjectMapper result = new ObjectMapper();
        result.addMixIn(TestBean.class, TestBeanMixin.class);
        return result;
    }
}

This code will produce short names for you POJO fields everywhere. and to implement different behavior for different request we have to add new custom annotation like this:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MixIn {}

Controller will look like this:

@Path("test")
public class MyResource {

    @GET 
    @MixIn // <== Here is important part
    @Produces(MediaType.APPLICATION_JSON )
    public Response  getShortName() {
        return Response.ok(demoObj()).build();
    }

    @POST
    @Produces(MediaType.APPLICATION_JSON )
    public Response  postLongName() {
        return Response.ok(demoObj()).build();
    }
}

And our MixInJacksonJsonProvider will have 2 more @Override:

    //.. same as before

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return super.isReadable(type, genericType, annotations, mediaType) && hasMixInAnnotation(annotations);
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return super.isWriteable(type, genericType, annotations, mediaType) && hasMixInAnnotation(annotations);
    }
    public static boolean hasMixInAnnotation(Annotation[] annotations){
        for(Annotation annotation: annotations){
            if (annotation instanceof MixIn){
                return true;
            }
        }
        return false;
    }
}

Here is demo code for you to play: https://github.com/varren/jersey2-jacksonsetup/tree/master/src/main/java/ru/varren

like image 131
varren Avatar answered Oct 19 '22 23:10

varren