2011-02-13 19 views
39

me gustaría Jackson para deserializar una clase con el siguiente constructor:Patrón Jackson + Builder?

public Clinic(String name, Address address) 

deserializar el primer argumento es fácil. El problema es que la Dirección se define como:

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(); 
    } 
} 

y se construye así: new Address.Builder().setCity("foo").setCountry("bar").create();

¿Hay una manera de conseguir pares de valores clave de Jackson con el fin de construir la Dirección mí mismo? Alternativamente, ¿hay alguna forma de que Jackson use la clase de Constructor?

Respuesta

6

que terminó la aplicación de este uso de la @JsonDeserialize de la siguiente manera:

@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(); 
    } 
} 
2

Actualmente no hay soporte para el patrón del generador, aunque se solicitó hace bastante tiempo (y finalmente se presentó el problema http://jira.codehaus.org/browse/JACKSON-469 de Jira) - es algo que se puede agregar para la versión 1.8 si hay suficiente demanda (marca ¡Seguro que votarás en Jira!). Es una característica adicional razonable, y solo se retrasa por la cantidad de tiempo que tienen los desarrolladores. Pero creo que sería una gran adición.

+1

Codehaus ya no tiene Jira disponible, pero el problema vinculado se describe aquí: http://wiki.fasterxml.com/JacksonFeatureBuilderPattern – Paul

+0

El soporte para el patrón Builder se ha agregado hace mucho tiempo, en algo como Jackson 2.2. – StaxMan

66

Mientras usted está utilizando Jackson 2+, entonces ahora hay built in support for this.

En primer lugar es necesario agregar esta anotación a su clase Address:

@JsonDeserialize(builder = Address.Builder.class) 

Luego hay que añadir esta anotación a su clase Builder:

@JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set") 

puede omitir esta segunda anotación de si se complacen en cambiar el nombre del método de creación de su Creador para compilar, y los configuradores de su Constructor con el prefijo, en lugar de establecerlo.

ejemplo completo:

@JsonDeserialize(builder = Address.Builder.class) 
public class Address 
{ 
    private Address(Map<LocationType, String> components) 
    ... 

    @JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set") 
    public static class Builder 
    { 
    public Builder setCity(String value); 
    public Builder setCountry(String value); 
    public Address create(); 
    } 
} 
+0

¡Gracias por la actualización! – Gili

+8

Si desea deshacerse de la anotación '@ JsonPOJOBuilder', cambie el nombre de" create "por" build "y anote cada uno de los setters del constructor con' @ JsonProperty'. –

+0

esto es dorado. Gracias. –

15

La respuesta de @Rupert Madden-Abbott obras. Sin embargo, si usted tiene un constructor no predeterminado, por ejemplo,

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

entonces usted debe anotar los parámetros de la siguiente manera:

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

Una solución que era adecuado para mí en este caso (he usado " Lombok "anotación del constructor".

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

Espero que sea útil para usted también.