2014-02-19 6 views
3

Я разрабатываю веб-сервис с использованием JAX-RS API с Джерси 1.17 в качестве моей реализации.Джерси производит непредвиденный тип носителя по умолчанию при бросании WebApplicationException

Я хочу, чтобы у клиентов был выбор между JSON и XML, которые они задают, используя HTTP-заголовок Accept. Я хочу, чтобы JSON был по умолчанию, когда клиент не включил заголовок Accept в запрос. Я попытался достичь этого, разместив MediaType.APPLICATION_JSON до MediaType.APPLICATION_XML в аннотации Produces.

Это похоже на работу в нормальных условиях:

$ curl 'http://localhost:8080/webservice/Bob' 
{"text":"Hello, Bob"} 

$ curl -H'Accept: application/json' 'http://localhost:8080/webservice/Bob' 
{"text":"Hello, Bob"} 

$ curl -H'Accept: application/xml' 'http://localhost:8080/webservice/Bob' 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Greeting text="Hello, Bob"/> 

Но если я бросаю WebApplicationException из конструктора моего класса ресурсов, по умолчанию типа ответа СМИ на XML:

$ curl 'http://localhost:8080/webservice/Vader' 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Error message="Illegal name"/> 

Если клиент включает в себя заголовок Accept, тип носителя указан правильно:

$ curl -H'Accept: application/json' 'http://localhost:8080/webservice/Vader' 
{"message":"Illegal name"} 

Как настроить Джерси для использования по умолчанию даже для ошибок, которые возникают из конструктора класса ресурсов?

Вот код моего класса ресурса (full example on GitHub):

package org.example.errorhandling; 

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.PathParam; 
import javax.ws.rs.Produces; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.Status; 

import org.example.errorhandling.repr.Error; 
import org.example.errorhandling.repr.Greeting; 

@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) 
@Path("/{name}") 
public class Greeter { 
    private final String name; 

    public Greeter(@PathParam("name") String name) { 
     if ("Vader".equals(name)) { 
      Error error = new Error(); 
      error.message = "Illegal name"; 
      Response errorResponse = Response.status(Status.BAD_REQUEST).entity(error).build(); 
      throw new WebApplicationException(errorResponse); 
     } else { 
      this.name = name; 
     } 
    } 

    @GET 
    public Response greet() { 
     Greeting greeting = new Greeting(); 
     greeting.text = "Hello, " + name; 
     return Response.ok(greeting).build(); 
    } 
} 
+1

Почему вы используете конструктор, а не 'greet' метод получить' @PathParam («имя») '? –

+0

@ LutzHorn В моем реальном веб-сервисе я захватываю '@PathParam (« имя »)' в конструкторе, чтобы выставить несколько подресурсов. В моем конструкторе я просматриваю объект, идентифицированный 'name' в бэкэнд-системе, и я хочу немедленно отправить исключение, если сбой поиска. – glerup

ответ

0

Эта проблема имеет временное решение из-за suggestion от usul_.

Обходным путем является использование механизма selectVariant() для программного выбора типа носителя, соответствующего заголовку Accept в запросе. Это позволяет принудительно использовать тип носителя по умолчанию за счет повторения предпочтительного порядка.

Вот конструктор модифицирован, чтобы использовать эту технику (full code on GitHub):

public Greeter(@PathParam("name") String name, @Context Request request) { 
    if ("Vader".equals(name)) { 
     Error error = new Error(); 
     error.message = "Illegal name"; 
     List<Variant> variants = Variant.mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).add().build(); 
     Variant variant = request.selectVariant(variants); 
     Response errorResponse = Response.status(Status.BAD_REQUEST).entity(error).variant(variant).build(); 
     throw new WebApplicationException(errorResponse); 
    } else { 
     this.name = name; 
    } 
} 
0

Вы пробовали использовать Джерси Exception Картостроители? Пример: https://github.com/jersey/jersey/blob/master/examples/exception-mapping/src/main/java/org/glassfish/jersey/examples/exception/Exceptions.java

+0

Я просто попытался использовать блок отображения исключений ([код на GitHub] (https://github.com/glerup/jersey-error-handling-sample-app/tree/experiment/error-mapping)). Но поведение такое же, порядок носителей для ресурса, похоже, игнорируется. – glerup

+0

У вас есть ответ, и вы можете установить тип ответа –

+0

Вы хотите сказать, что я должен объявить '@HeaderParam (« Принять »)' и попытаться интерпретировать заголовок 'Accept'? Это звучит как хак. Реализация JAX-RS должна сделать это для меня. – glerup

Смежные вопросы