JAX/Jersey Custom error code in Response

27,417

Solution 1

To do this in Jersey you have the concept of WebApplicationException class. One method is to simply extend this class and all one of the methods to set the error text that is returned. In your case this would be:

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;


public class UnauthorizedException extends WebApplicationException {

    /**
      * Create a HTTP 401 (Unauthorized) exception.
     */
     public UnauthorizedException() {
         super(Response.status(Status.UNAUTHORIZED).build());
     }

     /**
      * Create a HTTP 404 (Not Found) exception.
      * @param message the String that is the entity of the 404 response.
      */
     public UnauthorizedException(String message) {
         super(Response.status(Status.UNAUTHORIZED).entity(message).type("text/plain").build());
     }

}

Now in your code that implements the rest service you would simply throw a new exception of this type, passing in the text value in the constructor e.g.

throw new UnauthorizedException("Authorization Required");

That can create a class like this for each of your web exceptions and throw in a similar fashion.

This is also explained in the Jersey user guide - although the code is actually slightly incorrect:

https://jersey.github.io/nonav/documentation/latest/user-guide.html/#d4e435

Solution 2

I'm not sure JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services already covered this or not.

You might have to extend the Response.StatusType for this.

public abstract class AbstractStatusType implements StatusType {

    public AbstractStatusType(final Family family, final int statusCode,
                              final String reasonPhrase) {
        super();

        this.family = family;
        this.statusCode = statusCode;
        this.reasonPhrase = reasonPhrase;
    }

    protected AbstractStatusType(final Status status,
                                 final String reasonPhrase) {
        this(status.getFamily(), status.getStatusCode(), reasonPhrase);
    }

    @Override
    public Family getFamily() { return family; }

    @Override
    public String getReasonPhrase() { return reasonPhrase; }

    @Override
    public int getStatusCode() { return statusCode; }

    public ResponseBuilder responseBuilder() { return Response.status(this); }

    public Response build() { return responseBuilder().build(); }

    public WebApplicationException except() {
        return new WebApplicationException(build());
    }

    private final Family family;
    private final int statusCode;
    private final String reasonPhrase;
}

And here are some extended statust types.

public class BadRequest400 extends AbstractStatusType {

    public BadRequest400(final String reasonPhrase) {
        super(Status.BAD_REQUEST, reasonPhrase);
    }
}

public class NotFound404 extends AbstractStatusType {

    public NotFound404(final String reasonPhrase) {
        super(Status.NOT_FOUND, reasonPhrase);
    }
}

This is how I do.

@POST
public Response create(final MyEntity entity) {

    throw new BadRequest400("bad ass").except();
}

@GET
public MyEntity read(@QueryParam("id") final long id) {

    throw new NotFound404("ass ignorant").except();
}

// Disclaimer
// I'm not a native English speaker.
// I don't know what 'bad ass' or 'ass ignorant' means.
Share:
27,417
cassiomolin
Author by

cassiomolin

I � Unicode. Blog | GitHub | LinkedIn

Updated on August 10, 2022

Comments

  • cassiomolin
    cassiomolin almost 2 years

    In Jersey, how can we 'replace' the status string associated with a known status code?

    e.g.

    return Response.status(401).build();
    

    generates a HTTP response that contains:

    HTTP/1.1 401 Unauthorized
    

    I (not me, but the client application) would like to see the response as:

    HTTP/1.1 401 Authorization Required
    

    I tried the following approaches but in vain:

    1) This just adds the String in the body of the HTTP response

    return Response.status(401).entity("Authorization Required").build();
    

    2) Same result with this too:

    ResponseBuilder rb = Response.status(401);
    rb = rb.tag("Authorization Required");
    return rb.build();
    

    Appreciate your help!

    -spd

  • Jin Kwon
    Jin Kwon almost 11 years
    Didn't the OP ask the way other than entity(message)?
  • TWiStErRob
    TWiStErRob almost 11 years
    Well put, thank you for making me see that Status has an interface which I can mess with!
  • TWiStErRob
    TWiStErRob almost 11 years
    Agree with @JinKwon, how is this different than 1) in OP's question?
  • Ripu Daman
    Ripu Daman almost 9 years
    This approach doesn't seem to work with Jersey as it has a class "com.sun.jersey.core.spi.factory.ResponseImpl" which has its own logic to get the StatusType.