0

我正在构建一个 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。

当我删除@JsonIdentityInfoand@JsonIdentityReference时,这个 JSON 字符串可以正常工作,并且我的父级将被更新(但随后我会丢失我的简化答案并且还会出现无限循环问题)。

因此,如果我将我的 JSON 字符串调整为:

'{"parent":{"hostname":"parenthostname"}}'

更新工作正常。但我想让简化(展开)版本工作。有任何想法吗?我很感谢任何提示。

我正在使用休眠 4.2.4 和杰克逊 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);

这是我在这里的第一个问题,所以如果我的问题可能不完全清楚,请不要过分评判我;)

4

1 回答 1

2

我用一种解决方法解决了它。为了传递和接收我想要的、简化的 JSON 字符串,我现在使用@JsonSetter@JsonProperty.

另请参阅此答案

/**
 * 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;
    }
}
于 2015-03-31T07:06:06.153 回答