53 votes

Désérialisation de JSON en objet avec des méthodes surchargées en utilisant Jackson

J'essaie de désérialiser un objet JSON stocké dans CouchDb en utilisant Jackson. Cet objet doit être désérialisé dans un pojo qui contient des méthodes surchargées. Lorsque j'essaie de récupérer l'objet dans Couch et de procéder à la désérialisation, j'obtiens l'exception suivante :

org.ektorp.DbAccessException : org.codehaus.jackson.map.JsonMappingException : Définitions de setter contradictoires pour propriété "multiplier" : com.db.commodities.framework.sdos.model.security.EqOpt#setMultiplier(1 params) vs com.db.commodities.framework.sdos.model.security.EqOpt#setMultiplier(1 paramètres)

J'ai essayé d'annoter le setter que je voudrais que Jackson utilise, mais cela ne semble pas avoir fonctionné.

@JsonProperty("multiplier")
public void setMultiplier(SDOSAttribute multiplier) {
     this.multiplier = multiplier;
}

public void setMultiplier(double multiplier) {
     this.multiplier.setValue(String.valueOf(multiplier));
}

Comment puis-je configurer Jackson pour qu'il désérialise correctement en utilisant une méthode spécifique ? Ou est-ce que j'aborde ce problème de la mauvaise façon ?

EDIT :

J'ai apporté les modifications suivantes. Cela semble fonctionner, mais c'est un peu plus laid. Si quelqu'un a une meilleure façon de procéder, n'hésitez pas à la partager et je l'accepterai volontiers.

@JsonProperty("multiplier")
protected void setMultiplierAttribute(SDOSAttribute multiplier) {
    this.multiplier = multiplier;
}

@JsonIgnore
public void setMultiplier(double multiplier) {
    this.multiplier.setValue(String.valueOf(multiplier));
}

0 votes

Oui, c'est une solution valable. Je suis d'accord sur le fait que ce serait bien si l'inférence était utilisée de telle sorte que si une seule alternative était explicitement indiquée, les autres pourraient être ignorées en cas d'ambiguïté de la surcharge -- je peux ajouter une demande de fonctionnalité Jira pour cela.

0 votes

Autre chose : il est intéressant que le problème de la surcharge se pose ici, puisque Jackson autorise en fait une surcharge limitée. Plus précisément, si l'argument était int ou long (au lieu de double), le problème ne se poserait pas. Mais les autres types primitifs (double, float, boolean, char, byte, short) ne sont pas supportés de cette manière ; bien que float et double devraient probablement l'être. Avec int et long, la différence est résolue sur la base de ce que JSON a -- les objets JSON utilisent le setter POJO ; JSON numérote int ou long.

55voto

Programmer Bruce Points 16306

Il n'est pas nécessaire de changer le nom de la méthode setter pour éviter toute ambiguïté. Sinon, vous êtes sur la bonne voie avec @JsonIgnore . Avec @JsonIgnore sur toutes les méthodes du même nom à ignorer, celle à utiliser n'a pas besoin de l'attribut @JsonProperty annotation.

Voici un exemple simple pour démontrer ce point.

input.json : {"value":"forty-two"}

Foo.java :

import java.io.File;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  String value;

  public String getValue() {return value;}
  public void setValue(String value) {this.value = value;}

  @JsonIgnore
  public void setValue(int value) {this.value = String.valueOf(value);}

  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    Foo foo = mapper.readValue(new File("input.json"), Foo.class);
    System.out.println(mapper.writeValueAsString(foo));
  }
}

Si vous ne souhaitez pas modifier les défenses POJO vierges avec une annotation Jackson, vous pouvez utiliser une annotation MixIn .

import java.io.File;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  String value;

  public String getValue() {return value;}
  public void setValue(String value) {this.value = value;}
  public void setValue(int value) {this.value = String.valueOf(value);}

  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.getDeserializationConfig().addMixInAnnotations(Foo.class, IgnoreFooSetValueIntMixIn.class);
    Foo foo = mapper.readValue(new File("input.json"), Foo.class);
    System.out.println(mapper.writeValueAsString(foo));
  }
}

abstract class IgnoreFooSetValueIntMixIn
{
  @JsonIgnore public abstract void setValue(int value);
}

0 votes

Merci, c'est exactement ce que je cherchais.

4 votes

Qu'en est-il lorsque vous ne pouvez pas modifier la classe, lorsqu'il s'agit d'une tierce partie ? Existe-t-il une méthode pour cela ?

1 votes

La fonction Mix-In de Jackson pourrait bien répondre à vos besoins. Elle vous permet d'annoter efficacement les définitions de types de tiers, sans altérer les originaux.

9voto

gribo Points 300

Dans Jackson > 2.4, utilisez directement :

mapper.addMixIn(Foo.class, IgnoreFooSetValueIntMixIn.class);

2voto

lilalinux Points 445

Dans les cas où @JsonIgnore n'aide pas (j'ai actuellement un tel cas, mais je ne suis toujours pas sûr de la raison), il est également possible d'utiliser @XmlTransient à la place.

0voto

user17754330 Points 1
@JsonSetter
public void setMultiplier(SDOSAttribute multiplier) {
     this.multiplier = multiplier;
}

public void setMultiplier(double multiplier) {
     this.multiplier.setValue(String.valueOf(multiplier));
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X