泽西岛:没有找到适合类型 [简单类型,class 事物] 的构造函数:无法从 JSON 对象实例化
Jersey: No suitable constructor found for type [simple type, class Thing]: can not instantiate from JSON object
我有一个资源,方法如下:
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("/add")
public Response putThing(Thing thing) {
try {
//Do something with Thing object
return Response.status(HttpStatus.SC_OK).build();
} catch (Exception e) {
log.error("Request failed", e);
return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
}
}
事物:
public class Thing {
private final String symbol;
private final String name;
public Stock(String symbol, String name) {
this.symbol = symbol;
this.name = name;
}
public String getSymbol() {
return this.symbol;
}
public String getName() {
return this.name;
}
}
当我发出如下 PUT 请求时:
PUT /rest/add HTTP/1.1
Host: localhost:8135
Content-Type: application/json
Cache-Control: no-cache
{"symbol":"some symbol","name":"some name"}
我收到以下回复:
No suitable constructor found for type [simple type, class Thing]: can
not instantiate from JSON object (missing default constructor or
creator, or perhaps need to add/enable type information?)
为什么 Jersey/Jackson 没有将我的 JSON 对象反序列化到我的 POJO 中?
您需要一个无参数的构造函数和 setter,或者使用 @JsonCreator
。最简单的事情就是添加带有设置器的无参数。反序列化时杰克逊需要二传手。对于序列化,所需要的只是吸气剂。
编辑
为了保持不可变,您可以在构造函数上使用 @JsonCreator
。例如
@JsonCreator
public Thing(@JsonProperty("symbol") String symbol,
@JsonProperty("name") String name) {
this.symbol = symbol;
this.name = name;
}
我不是绝对肯定,但我认为就是这样。
Jackson 想要的工作方式是:它使用默认(无参数)构造函数创建对象。然后它使用 setter 来设置每个实例变量。这可能看起来很长,但它确实是唯一的方法,因为杰克逊真的不够聪明,无法弄清楚传递构造函数参数的顺序。所以你的代码有两个主要问题(好吧,三个,但是我将假设您的 class 在您为发布进行大部分清理之前被称为 Stock ;-))。
1. 你需要一个无参数的构造函数。据我所知,java 提供了一个默认构造函数,如果你不写的话,但是一旦你创建任何构造函数,默认的无参数构造函数就会消失。
2. 您的实例变量需要设置器(并且使它们 public 不够好,它们必须有实际的设置器)。哦,看起来你的实例变量是最终的,那是行不通的。我最喜欢的管理所有 copy/pasted setter 的方法是使用一个名为 lombok 的库。不管怎样,现在你只需要那些二传手。
我有一个资源,方法如下:
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("/add")
public Response putThing(Thing thing) {
try {
//Do something with Thing object
return Response.status(HttpStatus.SC_OK).build();
} catch (Exception e) {
log.error("Request failed", e);
return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
}
}
事物:
public class Thing {
private final String symbol;
private final String name;
public Stock(String symbol, String name) {
this.symbol = symbol;
this.name = name;
}
public String getSymbol() {
return this.symbol;
}
public String getName() {
return this.name;
}
}
当我发出如下 PUT 请求时:
PUT /rest/add HTTP/1.1
Host: localhost:8135
Content-Type: application/json
Cache-Control: no-cache
{"symbol":"some symbol","name":"some name"}
我收到以下回复:
No suitable constructor found for type [simple type, class Thing]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
为什么 Jersey/Jackson 没有将我的 JSON 对象反序列化到我的 POJO 中?
您需要一个无参数的构造函数和 setter,或者使用 @JsonCreator
。最简单的事情就是添加带有设置器的无参数。反序列化时杰克逊需要二传手。对于序列化,所需要的只是吸气剂。
编辑
为了保持不可变,您可以在构造函数上使用 @JsonCreator
。例如
@JsonCreator
public Thing(@JsonProperty("symbol") String symbol,
@JsonProperty("name") String name) {
this.symbol = symbol;
this.name = name;
}
我不是绝对肯定,但我认为就是这样。
Jackson 想要的工作方式是:它使用默认(无参数)构造函数创建对象。然后它使用 setter 来设置每个实例变量。这可能看起来很长,但它确实是唯一的方法,因为杰克逊真的不够聪明,无法弄清楚传递构造函数参数的顺序。所以你的代码有两个主要问题(好吧,三个,但是我将假设您的 class 在您为发布进行大部分清理之前被称为 Stock ;-))。
1. 你需要一个无参数的构造函数。据我所知,java 提供了一个默认构造函数,如果你不写的话,但是一旦你创建任何构造函数,默认的无参数构造函数就会消失。
2. 您的实例变量需要设置器(并且使它们 public 不够好,它们必须有实际的设置器)。哦,看起来你的实例变量是最终的,那是行不通的。我最喜欢的管理所有 copy/pasted setter 的方法是使用一个名为 lombok 的库。不管怎样,现在你只需要那些二传手。