Как вернуть HTTP 404 JSON/XML-ответ в JAX-RS (Джерси) на Tomcat?
У меня есть следующий код:
@Path("/users/{id}")
public class UserResource {
@Autowired
private UserDao userDao;
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public User getUser(@PathParam("id") int id) {
User user = userDao.getUserById(id);
if (user == null) {
throw new NotFoundException();
}
return user;
}
Если я запрашиваю пользователя, который не существует, например /users/1234
, с "Accept: application/json
", этот код возвращает ответ HTTP 404
, как и следовало ожидать, но возвращает Content-Type
на text/html
и сообщение тела html. Аннотация @Produces
игнорируется.
Это проблема кода или проблемы конфигурации?
Ответы
Ответ 1
Ваша аннотация @Produces
игнорируется, потому что неперехваченные исключения обрабатываются во время выполнения jax-rs с использованием предопределенного (по умолчанию) ExceptionMapper
. Если вы хотите настроить возвращенное сообщение в случае конкретного исключения, вы можете создать свой собственный ExceptionMapper
, чтобы справиться с этим. В вашем случае вам нужно обработать исключение NotFoundException
и запросить заголовок "accept" для запрошенного типа ответа:
@Provider
public class NotFoundExceptionHandler implements ExceptionMapper<NotFoundException>{
@Context
private HttpHeaders headers;
public Response toResponse(NotFoundException ex){
return Response.status(404).entity(yourMessage).type( getAcceptType()).build();
}
private String getAcceptType(){
List<MediaType> accepts = headers.getAcceptableMediaTypes();
if (accepts!=null && accepts.size() > 0) {
//choose one
}else {
//return a default one like Application/json
}
}
}
Ответ 2
Вы можете использовать ответ Response. Пример ниже:
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response get(@PathParam("id") Long id) {
ExampleEntity exampleEntity = getExampleEntityById(id);
if (exampleEntity != null) {
return Response.ok(exampleEntity).build();
}
return Response.status(Status.NOT_FOUND).build();
}
Ответ 3
что 404 возвращается вашим сервером, так как ожидается, что вы передадите вещи в следующей форме
/users/{id}
но вы передаете его как
/users/user/{id}
какой ресурс вообще не существует
попробуйте доступ к ресурсу как /users/1234
EDIT:
создать класс, например
class RestResponse<T>{
private String status;
private String message;
private List<T> objectList;
//gettrs and setters
}
теперь, если вы хотите отклик для User
, вы можете создать его как следующий
RestResponse<User> resp = new RestResponse<User>();
resp.setStatus("400");
resp.setMessage("User does not exist");
и подпись вашего метода отдыха будет выглядеть следующим образом
public RestResponse<User> getUser(@PathParam("id") int id)
в то время как в случае успешного ответа вы можете установить такие вещи, как
RestResponse<User> resp = new RestResponse<User>();
List<User> userList = new ArrayList<User>();
userList.add(user);//the user object you want to return
resp.setStatus("200");
resp.setMessage("User exist");
resp.setObjectList(userList);
Ответ 4
Просто это сработало для меня - ничего необычного. Это было с Jboss EAP 7 и JAX-RS:
jsonText = "{\n" + " \"account\": {\n" + " \"billing_account\": \"" + ipResponse.getResult().getParentGUID() + "\",\n" + "}" + ",\n" + "}";
parser = new JSONParser();
//build our JSON response object
try {
jSONObject = (JSONObject) parser.parse(jsonText);
return Response.status(200).entity(jSONObject.toJSONString()).build();
} catch (ParseException e) {
e.printStackTrace();
jsonEText = "{\n" + " \"account\": {\n" + " \"billing_account\": \"" + e.getMessage() + "\",\n" + "}" + ",\n" + "}";
jSONObject = (JSONObject) parser.parse(jsonEText);
return Response.status(404).entity(jSONObject.toJSONString()).build();
}