Jackson préfère constructeur privé sur @JsonCreator lors de la désérialisation d'une classe avec @JsonValue
J'ai une simple classe avec un constructeur privé et statique de l'usine. Je veux la classe de sérialiser comme un nombre, donc j'ai annoté de la lecture pour le champ avec @JsonValue
. Toutefois, Jackson semble préférer le constructeur privé au cours de la statique de l'usine, même quand je annoter la statique de l'usine avec @JsonCreator
. Il fonctionne si je annoter le constructeur privé avec @JsonIgnore
, mais qui se sent un peu.
J'ai vu quelques messages affirmant que @JsonCreator
ne fonctionne que si les paramètres sont annotés avec @JsonProperty
; cependant, cela semble être le cas pour les objets sérialisés comme objets JSON. Cet objet est sérialisé comme un nombre, et il n'est donc pas la propriété de fournir à l'annotation.
Est-il quelque chose que je suis absent?
exemple de classe:
package com.example;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.base.Preconditions;
public class NonNegative {
private final double n;
private NonNegative(double n) {
this.n = n;
}
@JsonCreator
public static NonNegative checked(double n) {
Preconditions.checkArgument(n >= 0.0);
return new NonNegative(n);
}
@JsonValue
public double getValue() {
return n;
}
@Override
public int hashCode() {
return Objects.hash(n);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof NonNegative) {
NonNegative that = (NonNegative) obj;
return Objects.equals(n, that.n);
}
return false;
}
}
exemple tests:
package com.example;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class NonNegativeTest {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
public void itSerializesAndDeserializes() throws Exception {
NonNegative nonNegative = NonNegative.checked(0.5);
assertThat(MAPPER.readValue(MAPPER.writeValueAsString(nonNegative), NonNegative.class)).isEqualTo(nonNegative);
}
/* This test fails. */
@Test(expected = JsonMappingException.class)
public void itDoesNotDeserializeANegativeNumber() throws Exception {
MAPPER.readValue(MAPPER.writeValueAsString(-0.5), NonNegative.class);
}
}
J'ai. Il n'a pas aidé.
Peut-être.
OriginalL'auteur NickAldwin | 2014-12-19
Vous devez vous connecter pour publier un commentaire.
En effet Jackson remplace JsonCreator méthode avec la méthode de constructeur, dans le cas où si le paramètre n'est Java de type standard. Je dirais que c'est un bug dans BasicDeserializerFactory#_handleSingleArgumentConstructor méthode.
Donc, le problème, c'est que le constructeur a une plus grande priorité statique de l'usine de la méthode dans le cas où si que constructeur et statique de la méthode de fabrique a régulier de type Java. Il ya quelques façons de le contourner.
Définir créateur niveau de visibilité NON_PRIVATE:
Deuxième façon est de supprimer statique méthode de fabrique et d'utilisation du constructeur. J'ai déménagé conditions Préalables.checkArgument pour le constructeur (il ne fait pas beaucoup... il suffit de jeter un IllegalArgumentException si la condition n'est pas satisfaite):
Une autre façon est d'utiliser @JsonIgnore annotation, mais vous mentionnez que vous n'aimez pas cette approche 🙂
Mise à jour j'ai connecté un bug: https://github.com/FasterXML/jackson-databind/issues/660
Mise à jour Jackson bug qui préfère constructeur plus statique usine méthode a été résolu: https://github.com/FasterXML/jackson-databind/commit/257ae1c7a88c5ccec2882433a39c0df1de2b73aa
Une autre façon est de modifier le constructeur de sorte qu'il ne sera pas appelé par Jackson, par exemple, d'ajouter un autre argument (peut-être un mannequin). Je ne vois pas en quoi c'est mieux que
@JsonIgnore
...OriginalL'auteur Ilya Ovesnov