简体   繁体   中英

JAX-RS Custom JSON representation of primitive Resource return type

Suppose we have a service with the following contract:

public interface CategoryService {

    public int createNew(String languageCode, String name, String descriptionMarkdown, Integer parentCategoryID, String createdByUserName) throws ServiceException;

};

How do I map the int return type to produce a JSON value like the following?

PS: I know that the createNew method will have to be an HTTP POST request (annotation @POST ). Assumes annotations are there. I just need the response representation.

{"id": 1}

Not sure if it's a good idea. Would be much better if you'll create new JAX-RS resource and designated entity-class to response with.
Still, if you want to mix marshalling with model, you could write your own MessageBodyWriter. For example:

@Produces("application/json")
public class IntWriter implements MessageBodyWriter<Integer> {

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        boolean intAsID = false;
        for (Annotation a : annotations) {
            if (a.annotationType().getCanonicalName().equals("com.blabla.IntAsID")) {
                intAsID = true;
                break;
            }
        }
        return intAsID && (type == Integer.class);
    }

    @Override
    public long getSize(Integer integer, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return 0;
    }

    @Override
    public void writeTo(Integer integer, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
        JsonGenerator generator = Json.createGenerator(entityStream);
        generator.writeStartObject()
                .write("id", integer)
                .writeEnd()
                .flush();
    }
}

Several keypoints here.
1.

Don't forget to register this writer in your configuration.

public class ServerConfig extends Application {

    private static final Set<Class<?>> classes
            = new HashSet<>();

    static {
        //register your resources
        classes.add(Test.class);
        //register message body writer
        classes.add(IntWriter.class);
    }

    @Override
    public Set<Class<?>> getClasses() {
        return classes;
    }

}

2.

If you don't want to use use this writer for every resource returning int. Create some special annotation for your resource (for example IntAsID).

@Retention(RetentionPolicy.RUNTIME)
public @interface IntAsID {}

Don't forget to set correct retention policy. And check presence of this annotation in isWriteable method. Like I did in my example.
And yes, add this annotation to your resource:

public interface CategoryService {

    @IntAsID
    public int createNew(String languageCode, String name, String descriptionMarkdown, Integer parentCategoryID, String createdByUserName) throws ServiceException;

};

3.

Use @Produces annotation. That will help your JAX-RS provider to don't check this writer in cases then Resource should produce not JSON, but something else.

4.

Don't care about getSize() method. Its result is ignored now (at least in Jersey).

5.

Don't close entityStream in writeTo method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM