我正在构建一个RESTful服务来查看服务器关系(一个服务器可以包含另一个服务器作为其父服务器)。该服务接受CRUD命令的JSON字符串。
我在服务器对象中使用@JsonIdentityInfo
和@JsonIdentityReference
,以便用户收到如下简化的JSON答案:
{"hostname":"childhostname", "parent":"parenthostname"}
作为父母我只获得父母的主人名而不是父母对象 - 这正是我想要的,并且工作正常。
尝试反序列化更新命令时(尝试更新父级时),我的问题就出现了。如果我寄这个:
curl -i -X POST -H 'Content-Type: application/json' -d '{"parent":"parenthostname"}' http://localhost:8080/myRestService/rest/servers/childhostname
什么都没发生 - 父母将不会被设置。问题在于提供的JSON字符串:
{"parent":"parenthostname"}
调试hibernate 2.4.4源代码后,我发现我的JSON字符串生成com.fasterxml.jackson.databind.deser.UnresolvedForwardReference: Could not resolve Object Id [parenthostname]
。不抛出此异常,但将返回null。
当我删除@JsonIdentityInfo
和@JsonIdentityReference
时,此JSON字符串工作正常,我的父级将更新(但后来我失去了简化的答案,并且还会遇到无限循环问题)。
所以,如果我将我的JSON字符串调整为:
'{"parent":{"hostname":"parenthostname"}}'
更新工作正常。但我希望简化(解包)版本正常工作。有任何想法吗?我很感激任何提示。
我使用的是Hibernate 4.2.4和Jackson 2.4.4
这是我的(简化)服务器类:
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="hostname")
public class Server extends A_Hardware {
@NaturalId
@Column(name="hostname", nullable=false, unique=true)
private String hostname = null;
@ManyToOne
@JsonIdentityReference(alwaysAsId = true)
private Server parent = null;
@OneToMany(fetch = FetchType.LAZY, mappedBy="parent")
@JsonIdentityReference(alwaysAsId = true)
private Set<Server> childServers = new HashSet<Server>();
[...]
// standard getters and setters
这是我的RESTful服务的更新类:
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("{hostname}")
public Response update(@PathParam("hostname") final String hostname, JsonParser json){
Server s = null;
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
try{
s = mapper.readValue(json, Server.class);
这是我在这里的第一个问题,所以如果我的问题可能不完全清楚,请不要过分评判我;)
答案 0 :(得分:2)
我有点解决了它的解决方法。为了提供和接收我想要的,简化的JSON字符串,我现在使用@JsonSetter
和@JsonProperty
。
另见this answer。
/**
* JSON Helper method, used by jackson. Makes it possible to add a parent by just delivering the hostname, no need for the whole object.
*
* This setter enables:
* {"parent":"hostnameOfParent"}
*
* no need for this:
* {"parent":{"hostname":"hostnameOfParent"}}
*/
@JsonSetter
private void setParentHostname(String hostname) {
if(hostname!=null){
this.parent = new Server(hostname);
} else {
this.parent = null;
}
}
/**
* Used by jackson to deserialize a parent only with its hostname
*
* With this getter, only the hostname of the parent is being returned and not the whole parent object
*/
@JsonProperty("parent")
private String getParentHostname(){
if(parent!=null){
return parent.getHostname();
} else {
return null;
}
}