Cómo PUBLICAR un objeto JSON en un servicio JAX-RS


Estoy usando la implementación de Jersey de JAX-RS. Me gustaría publicar un objeto JSON en este servicio, pero estoy recibiendo un código de error 415 Tipo de medio no compatible. ¿Qué me estoy perdiendo?

Aquí está mi código:

@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;
    }
}

Aquí está el objeto de Orden:

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

Una solicitud GET como esta funciona perfectamente y devuelve un pedido en formato JSON:

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

Sin embargo, una solicitud POST como esta devuelve un 415:

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

{
    "id": "123",
    "symbol": "AAPL",
    "side": "Buy",
    "quantity": "1000"
}
Author: Elnur Abdurrakhimov, 2011-10-08

3 answers

La respuesta fue sorprendentemente simple. Tuve que agregar un encabezado Content-Type en la solicitud POST con un valor de application/json. Sin este encabezado Jersey no sabía qué hacer con el cuerpo de la solicitud (a pesar de la anotación @Consumes(MediaType.APPLICATION_JSON))!

 74
Author: Naresh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-07 21:56:10

Jersey hace el proceso muy fácil, mi clase de servicio funcionó bien con JSON, todo lo que tenía que hacer era agregar las dependencias en el 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;
    }
}

Y en el 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>
 11
Author: glm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-15 07:31:51

Me enfrenté al mismo error http 415 al enviar objetos, serializados en JSON, a través de solicitudes PUT/PUSH a mis servicios JAX-rs, en otras palabras, mi servidor no fue capaz de des-serializar los objetos desde JSON. En mi caso, el servidor fue capaz de serializar con éxito los mismos objetos en JSON al enviarlos a sus respuestas.

Como se mencionó en las otras respuestas, he establecido correctamente los encabezados Accept y Content-Type a application/json, pero no lo hace suficiente.

Solución

Simplemente olvidé un constructor predeterminado sin parámetros para mis objetos DTO. Sí, este es el mismo razonamiento detrás de los objetos @Entity, necesita un constructor sin parámetros para que el OR instancie objetos y rellene los campos más tarde.

Agregar el constructor sin parámetros a mis objetos DTO resolvió mi problema. Aquí sigue un ejemplo que se asemeja a mi código:

Incorrecto

@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;
    }
}

Derecha

@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;
    }
}

Perdí horas, espero que esto salve las tuyas; -)

 6
Author: Fabiano Tarlao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-04 11:04:44