Search code examples
jerseyjax-rs

Using jersey, how can I produce json for errors and octet stream for success


Short version of the question:

Using Jersey, how can I determine the @Produces type at runtime?

Long version of the question:

I wrote a REST call using jersy as follows:

@GET
@Path("/getVideo")
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON})
public Response getAllVideos(@QueryParam("videoID") Long videoID) throws ApiException, SQLException {
    --some code--
    Response r ...;
    return r;
}

If the user provides a valid videoID then this should return an mp4 file, hence the @Produces({MediaType.APPLICATION_OCTET_STREAM,. However, if an exception is thrown, such as a providing wrong videoID I want to return a json describing the exception.

The way it currently works is, that if a valid ID is provided, it returns a 200 with the mp4 file. But if an exception is thrown, it responds with a 500 and a message Could not find MessageBodyWriter for response object of type: com.my.package.Errors$CustomError of media type: application/octet-stream.

Based on the Jersey documentation the response's return type is determined is by the accept type of the request.

My problem is that I don't know in advance, when sending the request what type of response I want back (because I hope the request will be successful). Instead, I want to determine the response type at runtime based on whether or not an exception was thrown.

How can I do that?

(I think my question is similar to this question but I am not using Spring).


Solution

  • This will probably work because your exception says it couldn't find a message writer for CustomError

    @Provider
    @Produces(MediaType.APPLICATION_OCTET_STREAM) //I think you will have to leave this as octet_stream so jax-rs will pick as valid message writer
    public class CustomErrorBodyWriter implements MessageBodyWriter<CustomError> {
    
        @Override
        public boolean isWriteable(Class<?> type, Type genericType,
                                   Annotation[] annotations, MediaType mediaType) {
            return type == CustomError.class;
        }
    
        @Override
        public long getSize(CustomError customError, Class<?> type, Type genericType,
                            Annotation[] annotations, MediaType mediaType) {
            // deprecated by JAX-RS 2.0 and ignored by Jersey runtime
            return 0;
        }
    
        @Override
        public void writeTo(CustomError customError, Class<?> type, Type genericType, Annotation[] annotations,
                            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
                            OutputStream out) throws IOException, WebApplicationException {
    
            //manipulate the httpHeaders  to have content-type application/json
    
            //transalate customError and write it to OutputStream          
    
            Writer writer = new PrintWriter(out);
            writer.write("{ \"key\" : \"some random json to see if it works\" }");
    
    
            writer.flush();
            writer.close();
        }
    }