101 votes

Jackson + modèle de constructeur ?

J'aimerais que Jackson désérialise une classe avec le constructeur suivant :

 public Clinic(String name, Address address)

Désérialiser le premier argument est facile. Le problème est que l'adresse est définie comme :

 public class Address {
  private Address(Map<LocationType, String> components)
  ...

  public static class Builder {
    public Builder setCity(String value);
    public Builder setCountry(String value);
    public Address create();
  }
}

et est construit comme ceci : new Address.Builder().setCity("foo").setCountry("bar").create();

Existe-t-il un moyen d'obtenir des paires clé-valeur de Jackson afin de construire l'adresse moi-même ? Sinon, existe-t-il un moyen d'amener Jackson à utiliser la classe Builder elle-même ?

21voto

volatilevar Points 1218

La réponse de @Rupert Madden-Abbott fonctionne. Cependant, si vous avez un constructeur autre que celui par défaut, par exemple,

 Builder(String city, String country) {...}

Ensuite, vous devez annoter les paramètres comme ci-dessous :

 @JsonCreator
Builder(@JsonProperty("city")    String city, 
        @JsonProperty("country") String country) {...}

10voto

JustK K Points 119

Une solution qui me convenait dans ce cas (j'ai utilisé l'annotation du constructeur "Lombok").

 @Getter
@Builder(builderMethodName = "builder")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@JsonAutoDetect(
    fieldVisibility = JsonAutoDetect.Visibility.ANY,
    creatorVisibility = JsonAutoDetect.Visibility.ANY
)

J'espère que cela vous sera utile aussi.

7voto

Gili Points 14674

J'ai fini par implémenter cela en utilisant @JsonDeserialize comme suit :

 @JsonDeserialize(using = JacksonDeserializer.class)
public class Address
{...}

@JsonCachable
static class JacksonDeserializer extends JsonDeserializer<Address>
{
    @Override
    public Address deserialize(JsonParser parser, DeserializationContext context)
        throws IOException, JsonProcessingException
    {
        JsonToken token = parser.getCurrentToken();
        if (token != JsonToken.START_OBJECT)
        {
            throw new JsonMappingException("Expected START_OBJECT: " + token, parser.getCurrentLocation());
        }
        token = parser.nextToken();
        Builder result = new Builder();
        while (token != JsonToken.END_OBJECT)
        {
            if (token != JsonToken.FIELD_NAME)
            {
                throw new JsonMappingException("Expected FIELD_NAME: " + token, parser.getCurrentLocation());
            }
            LocationType key = LocationType.valueOf(parser.getText());

            token = parser.nextToken();
            if (token != JsonToken.VALUE_STRING)
            {
                throw new JsonMappingException("Expected VALUE_STRING: " + token, parser.getCurrentLocation());
            }
            String value = parser.getText();

            // Our Builder allows passing key-value pairs
            // alongside the normal setter methods.
            result.put(key, value);
            token = parser.nextToken();
        }
        return result.create();
    }
}

3voto

StaxMan Points 34626

Il n'y a actuellement pas de support pour le modèle de générateur, bien qu'il ait été demandé il y a un certain temps (et enfin le problème Jira http://jira.codehaus.org/browse/JACKSON-469 a été déposé) - c'est quelque chose qui peut être ajouté pour la version 1.8 si la demande est suffisante (assurez-vous de voter chez Jira !). C'est une fonctionnalité supplémentaire raisonnable, et seulement retardée par le temps dont disposent les développeurs. Mais je pense que ce serait un excellent ajout.

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