web-dev-qa-db-fra.com

Définition de valeurs par défaut sur les champs nuls lors du mappage avec Jackson

J'essaie de mapper des objets JSON en objets Java avec Jackson. Certains champs de l’objet JSON sont obligatoires (que je peux marquer avec @NotNull) et d’autres sont facultatifs.

Après le mappage avec Jackson, tous les champs non définis dans l'objet JSON auront une valeur NULL en Java. Existe-t-il une annotation similaire à @NotNull qui peut indiquer à Jackson de définir une valeur par défaut sur un membre de la classe Java, au cas où elle serait nulle?

Edit: Pour clarifier la question, voici un exemple de code.

L'objet Java:

class JavaObject {
    @NotNull
    public String notNullMember;

    @DefaultValue("Value")
    public String optionalMember;
}

L'objet JSON peut être soit:

{
    "notNullMember" : "notNull"
}

ou:

{
    "notNullMember" : "notNull",
    "optionalMember" : "optional"
}

Les annotations @DefaultValue sont juste pour montrer ce que je demande. Ce n'est pas une vraie annotation. Si l'objet JSON est comme dans le premier exemple, je souhaite que la valeur de la variable optionalMember soit "Value" et non null. Y at-il une annotation qui fait une telle chose?

41
gookman

Il n'y a pas d'annotation pour définir la valeur par défaut.
Vous pouvez définir la valeur par défaut uniquement au niveau de la classe Java: 

public class JavaObject 
{
    public String notNullMember;

    public String optionalMember = "Value";
}
53
Ilya

Une seule solution proposée conserve le default-value lorsque some-value:null a été défini explicitement (la lisibilité du POJO y est perdue et elle est maladroite)

Voici comment conserver le default-value et ne jamais le régler sur null

@JsonProperty("some-value")
public String someValue = "default-value";

@JsonSetter("some-value")
public void setSomeValue(String s) {
    if (s != null) { 
        someValue = s; 
    }
}
11
Sergey Voitovich

On dirait que la solution consiste à définir la valeur des propriétés à l'intérieur du constructeur par défaut. Donc, dans ce cas, la classe Java est:

class JavaObject {

    public JavaObject() {

        optionalMember = "Value";
    }

    @NotNull
    public String notNullMember;

    public String optionalMember;
}

Après le mappage avec Jackson, si la variable optionalMember est absente du JSON, sa valeur dans la classe Java est "Value".

Cependant, je suis toujours intéressé de savoir s'il existe une solution avec des annotations et sans le constructeur par défaut.

4
gookman

Rendre le membre privé et ajouter une paire setter/getter . Dans votre setter, si null, définissez la valeur par défaut à la place de .. .

class JavaObject {
    private static final String DEFAULT="Default Value";

    public JavaObject() {
    }

    @NotNull
    private String notNullMember;
    public void setNotNullMember(String value){
            if (value==null) { notNullMember=DEFAULT; return; }
            notNullMember=value;
            return;
    }

    public String getNotNullMember(){
            if (notNullMember==null) { return DEFAULT;}
            return notNullMember;
    }

    public String optionalMember;
}
2
Michael Joyner

Vous pouvez créer votre propre JsonDeserializer et annoter cette propriété avec @JsonDeserialize(as = DefaultZero.class)

f.e. pour BigDecimal par défaut ZERO:

classe statique publique DefaultZero étend JsonDeserializer {délégué final privé JsonDeserializer;

    public DefaultZero(JsonDeserializer<BigDecimal> delegate) {
        this.delegate = delegate;
    }

    @Override
    public BigDecimal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        return jsonParser.getDecimalValue();
    }

    @Override
    public BigDecimal getNullValue(DeserializationContext ctxt) throws JsonMappingException {
        return BigDecimal.ZERO;
    }
}

f.e.

class Sth {

   @JsonDeserialize(as = DefaultZero.class)
   BigDecimal property;
 }
1
Pau

J'ai eu un problème similaire, mais dans mon cas, la valeur par défaut était dans la base de données. Voici la solution pour cela:

 @Configuration
 public class AppConfiguration {
 @Autowired
 private AppConfigDao appConfigDao;

 @Bean
 public Jackson2ObjectMapperBuilder builder() {
   Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
       .deserializerByType(SomeDto.class, 
 new SomeDtoJsonDeserializer(appConfigDao.findDefaultValue()));
   return builder;
 }

Ensuite, dans SomeDtoJsonDeserializer, utilisez ObjectMapper pour désérialiser le json et définir la valeur par défaut si votre champ/objet est null.

0
Adrian