Как ОПУБЛИКОВАТЬ объект JSON в службе JAX-RS

#json #jersey #jax-rs

#json #джерси #jax-rs

Вопрос:

Я использую реализацию JAX-RS в Джерси. Я хотел бы ОПУБЛИКОВАТЬ объект JSON в этой службе, но я получаю код ошибки 415 Неподдерживаемый тип носителя. Чего мне не хватает?

Вот мой код:

 @Path("/orders")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class OrderResource {

    private static Map<Integer, Order> orders = new HashMap<Integer, Order>();

    @POST
    public void createOrder(Order order) {

        orders.put(order.id, order);
    }

    @GET
    @Path("/{id}")
    public Order getOrder(@PathParam("id") int id) {
        Order order = orders.get(id);
        if (order == null) {
            order = new Order(0, "Buy", "Unknown", 0);
        }
        return order;
    }
}
  

Вот объект Order:

 public class Order {
    public int id;
    public String side;
    public String symbol;
    public int quantity;
    ...
}
  

Запрос GET, подобный этому, работает отлично и возвращает заказ в формате JSON:

 GET http://localhost:8080/jaxrs-oms/rest/orders/123 HTTP/1.1
  

Однако запрос POST, подобный этому, возвращает 415:

 POST http://localhost:8080/jaxrs-oms/rest/orders HTTP/1.1

{
    "id": "123",
    "symbol": "AAPL",
    "side": "Buy",
    "quantity": "1000"
}
  

Ответ №1:

Ответ был на удивление простым. Мне пришлось добавить Content-Type заголовок в POST запрос со значением application/json . Без этого заголовка Джерси не знал, что делать с телом запроса (несмотря на @Consumes(MediaType.APPLICATION_JSON) аннотацию)!

Комментарии:

1. Аннотация Consumes определяет только то, что приемлемо для метода на стороне сервера (поэтому он действует для дальнейшей фильтрации запросов, у которых нет Content-Type: application / json в заголовке HTTP). Причина, по которой ваш запрос должен иметь Content-Type, независимо от использования метода, заключается в том, что MessageBodyReader библиотеки JSON, который вы используете, вероятно, пытается десериализовать тело запроса, только если оно имеет Content-Type: application/json (потому что MessageBodyReader, вероятно, имеет @Consumes(MediaType . APPLICATION_JSON на нем).

2. На случай, если кто-либо использует HttpClient от apache, вот как вы устанавливаете строку json: postMethod.setRequestEntity(new StringRequestEntity(jsonString, «application / json», null));

3. Я забыл добавить аннотацию @XmlRootElement поверх POJO (порядок классов в вашем случае)

4. У меня была точно такая же проблема, как и у вас, и Content-Type:application / json было недостаточно. Мне также пришлось настроить один JsonProvider в xml Spring Beans: <идентификатор компонента =»JsonProvider» class=»org.apache.cxf.jaxrs.provider.json.JsonProvider» > <имя свойства=»singleJaxbContext» значение =»true» /> <имя свойства =»extraClass»><список> <значение>package.to.class . Порядок </значение> </список> </свойство> </ компонент>

5. В моем случае мне пришлось внести следующие изменения: <br/> post.setEntity(new StringEntity(projdetailpojo.toString())); post.setHeader("Content-Type", "application/json"); HttpResponse response = client.execute(post);

Ответ №2:

Джерси упрощает процесс, мой класс service хорошо работал с JSON, все, что мне нужно было сделать, это добавить зависимости в pom.xml

 @Path("/customer")
public class CustomerService {

    private static Map<Integer, Customer> customers = new HashMap<Integer, Customer>();

    @POST
    @Path("save")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public SaveResult save(Customer c) {

        customers.put(c.getId(), c);

        SaveResult sr = new SaveResult();
        sr.sucess = true;
        return sr;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("{id}")
    public Customer getCustomer(@PathParam("id") int id) {
        Customer c = customers.get(id);
        if (c == null) {
            c = new Customer();
            c.setId(id * 3);
            c.setName("unknow "   id);
        }
        return c;
    }
}
  

И в pom.xml

 <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.7</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.7</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.7</version>
</dependency>
  

Ответ №3:

Я столкнулся с той же 415 ошибкой http при отправке объектов, сериализованных в JSON, через запросы PUT / PUSH в мои службы JAX-rs, другими словами, мой сервер не смог десериализовать объекты из JSON. В моем случае сервер смог успешно сериализовать одни и те же объекты в формате JSON при отправке их в свои ответы.

Как упоминалось в других ответах, я правильно установил заголовки Accept and Content-Type application/json , но этого недостаточно.

Решение

Я просто забыл конструктор по умолчанию без параметров для моих объектов DTO. Да, это та же причина, что и для объектов @Entity, вам нужен конструктор без параметров для ORM для создания экземпляров объектов и последующего заполнения полей.

Добавление конструктора без параметров к моим объектам DTO решило мою проблему. Ниже приведен пример, похожий на мой код:

Неправильно

 @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class NumberDTO {
    public NumberDTO(Number number) {
        this.number = number;
    }

    private Number number;

    public Number getNumber() {
        return number;
    }

    public void setNumber(Number string) {
        this.number = string;
    }
}
  

Правильно

 @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class NumberDTO {

    public NumberDTO() {
    }

    public NumberDTO(Number number) {
        this.number = number;
    }

    private Number number;

    public Number getNumber() {
        return number;
    }

    public void setNumber(Number string) {
        this.number = string;
    }
}
  

Я потерял часы, надеюсь, это спасет ваши 😉