web-dev-qa-db-fra.com

Sérialisation générique Java objet à JSON en utilisant Jackson

Quand j'ai essayé de convertir l'instance de classe suivante en JSON (en utilisant Jackson)

public class RPCRespond<Result> {

    private int code;
    private Result result;
    private boolean success;
    private String failureReason;

    public RPCRespond() {
        this.code = 0;
        this.success = true;
        this.result = null;
    }

    public RPCRespond(Result result) {
        this.code = 0;
        this.success = true;
        this.result = result;
    }

    public RPCRespond(int code, String failureReason) {
        this.code = code;
        this.success = false;
        this.failureReason = failureReason;
    }

    public RPCRespond(int code, String failureReason, Object... args) {
        this.code = code;
        this.success = false;
        this.failureReason = String.format(failureReason, args);
    }

    public Result getResult() {
        return result;
    }


    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getFailureReason() {
        return failureReason;
    }

    public void setFailureReason(String failureReason) {
        this.failureReason = failureReason;
    }

    public int getCode() {
        return code;
    }

    public boolean getSuccess() {
        return success;
    }

    @Transient
    public String getAsJSON() {

        String json = "";

        ObjectMapper mapper = new ObjectMapper();
        json = mapper.writeValueAsString(this) ; 

        return json ;
    }

}

il entre dans une boucle infinie de:

 sur Sun.reflect.GeneratedMethodAccessor48.invoke (Source inconnue) sur 
 Sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.Java:43) 
 sur Java.lang.reflect.Method .invoke (Method.Java:601) à 
 org.codehaus.jackson.map.ser.BeanPropertyWriter.get (BeanPropertyWriter.Java:483) 
 à 
 org.codehaus. jackson.map.ser.BeanPropertyWriter.serializeAsField (BeanPropertyWriter.Java:418) 
 à 
 org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields (BeanSerializerBase.Java:150) 
 sur 
 org.codehaus.jackson.map.ser.BeanSerializer.serialize (BeanSerializer.Java:112) 
 sur 
 org.codehaus.jackson.map.ser .StdSerializerProvider._serializeValue (StdSerializerProvider.Java:610) 
 À 
 Org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue (StdSerializerProvider.Java:256) 
 À 
 org.codehaus.jackson.map.ObjectMapper._configAndWriteValue (ObjectMapp er.Java:2566)
 à 
 org.codehaus.jackson.map.ObjectMapper.writeValueAsString (ObjectMapper.Java:2088) 

L'initiation du RPCRespond se fait par

User u = new User() ;
u.setFirstName("aaaa") ;
RPCRespond<User> result = new RPCRespond<User>(u) ;

result.setSuccess(true) ;

return result.getAsJSON() ;

Comment puis-je convertir RPCRespond en JSON?

21
oferbu

Par défaut, Jackson sérialisera via les méthodes get. Une fois qu'il atteint la méthode getAsJson, poom, boucle infinie. Marquez-le avec le @JsonIgnore annotation.

@JsonIgnore
public String getAsJSON() {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.writeValueAsString(this) ; 
}

Vous pouvez également configurer Jackson pour sérialiser en fonction des propriétés uniquement, ce qui peut éliminer le besoin de @JsonIgnore, mais cela peut ou non répondre à vos besoins.

I croyez le dernier Jackson permet le choix d'utiliser le Hibernate @Transient annotation, mais je ne sais pas comment le configurer (changement récent).

57
Dave Newton

Comme d'autres l'ont suggéré, cela est probablement dû à des références cycliques; par défaut, Jackson ne gère pas ces dépendances.

Vous pouvez soit ignorer la sérialisation de cette propriété, soit, s'il s'agit d'une liaison de type parent/enfant, l'annoter en tant que telle (voir l'entrée " références bidirectionnelles " sur Jackson Wiki pour plus de détails).

Pour ce que ça vaut, les types génériques ne provoquent pas cela (c'est-à-dire que ce n'est probablement qu'une coïncidence ici); les types cycliques sont parfaitement fins.

2
StaxMan