Reputation: 82
I am trying to set a response status of the following Jersey REST endpoint
@Path("/roles")
public interface IRoleService {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Role create(Role role);
}
Since it creates a new resource it would be appropriate if it returned Status code 201 but currently it returns 200.
The only way I found how to set the status code is to have the method return a javax.ws.rs.core.Response
and set it there, but I really do not want all of my interfaces to return a generic Response instead of the actual response object (in this case Role
).
Upvotes: 2
Views: 3209
Reputation: 373
Removed ElementType.Type.
@NameBinding
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
int DEFAULT_CODE = 0;
int code() default DEFAULT_CODE;
}
statusFilter class:
@Provider
public class StatusFilter implements ContainerResponseFilter {
private static Logger logger = LoggerFactory.getLogger(StatusFilter.class);
@Context
private ResourceInfo resourceInfo;
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
Status status = resourceInfo.getResourceMethod().getAnnotation(Status.class);
if(status!=null){
int code = status.code();
if(code != Status.DEFAULT_CODE && responseContext.getStatus() == 200) {
responseContext.setStatus(code);
}
}
}
}
Then use it in the resource interface method declaration
@POST
@Status(code = 201)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
GetUserResponse createUser(UserRequest userRequest);
Upvotes: 0
Reputation: 208994
One way would be to create a custom annotation and using a response filter to set the status. For example
Annotation
@NameBinding
@Target({METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
int DEFAULT_CODE = 0;
int code() default DEFAULT_CODE;
}
ContainerResponseFilter
@Status
@Provider
public class StatusFilter implements ContainerResponseFilter {
@Context
private ResourceInfo info;
@Override
public void filter(ContainerRequestContext req, ContainerResponseContext res) throws IOException {
Status status = getInterfaceAnnotation(info.getResourceMethod());
if (status != null) {
int code = status.code();
if (code != Status.DEFAULT_CODE && res.getStatus() == 200) {
res.setStatus(code);
}
}
}
private static Status getInterfaceAnnotation(Method resourceMethod) {
String methodName = resourceMethod.getName();
Class<?>[] paramTypes = resourceMethod.getParameterTypes();
Class<?> iface = resourceMethod.getDeclaringClass().getInterfaces()[0];
Method ifaceMethod;
try {
ifaceMethod = iface.getDeclaredMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
return null;
}
return ifaceMethod.getAnnotation(Status.class);
}
}
In the filter, we get the method with ResourceInfo
and do some reflection to get the @Status
annotation. The from there, can grab the status code and set it on the response.
Since it is a Name Binding filter, it will only be called for methods that are annotated with it. See more here.
Then to use it, just add the annotation to the method.
public interface ITestResource {
@GET
@Status(code=201)
String get();
}
The same could be done for headers if you need to add some custom headers.
Upvotes: 3