如何将 JSON 对象发布到 JAX-RS 服务

我使用的是 JAX-RS 的 Jersey 实现。我想发布一个 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"
}
176313 次浏览

The answer was surprisingly simple. I had to add a Content-Type header in the POST request with a value of application/json. Without this header Jersey did not know what to do with the request body (in spite of the @Consumes(MediaType.APPLICATION_JSON) annotation)!

Jersey makes the process very easy, my service class worked well with JSON, all I had to do is to add the dependencies in the 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;
}
}

And in the 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>

I faced the same 415 http error when sending objects, serialized into JSON, via PUT/PUSH requests to my JAX-rs services, in other words my server was not able to de-serialize the objects from JSON. In my case, the server was able to serialize successfully the same objects in JSON when sending them into its responses.

As mentioned in the other responses I have correctly set the Accept and Content-Type headers to application/json, but it doesn't suffice.

Solution

I simply forgot a default constructor with no parameters for my DTO objects. Yes this is the same reasoning behind @Entity objects, you need a constructor with no parameters for the ORM to instantiate objects and populate the fields later.

Adding the constructor with no parameters to my DTO objects solved my issue. Here follows an example that resembles my code:

Wrong

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

Right

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

I lost hours, I hope this'll save yours ;-)