Шаблон Джексона + Строителя? - PullRequest
68 голосов
/ 13 февраля 2011

Я бы хотел, чтобы Джексон десериализовал класс следующим конструктором:

public Clinic(String name, Address address)

Десериализация первого аргумента проста. Проблема в том, что Адрес определяется как:

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

и построен так: new Address.Builder().setCity("foo").setCountry("bar").create();

Есть ли способ получить пары ключ-значение от Джексона, чтобы сам построить адрес? В качестве альтернативы, есть ли способ заставить Джексона использовать сам класс Builder?

Ответы [ 5 ]

19 голосов
/ 01 августа 2014

Ответ от @Rupert Madden-Abbott работает.Однако, если у вас есть конструктор не по умолчанию, например,

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

, тогда вы должны аннотировать параметры следующим образом:

@JsonCreator
Builder(@JsonProperty("city")    String city, 
        @JsonProperty("country") String country) {...}
7 голосов
/ 14 февраля 2011

Я реализовал это с помощью @JsonDeserialize следующим образом:

@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();
    }
}
5 голосов
/ 06 марта 2018

Решение, которое мне подходит в этом случае (я использовал аннотацию строителя "Ломбок").

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

Надеюсь, тебе это тоже пригодится.

3 голосов
/ 13 февраля 2011

В настоящее время нет поддержки для шаблона сборки, хотя он был запрошен довольно давно (и, наконец, проблема Jira http://jira.codehaus.org/browse/JACKSON-469 была подана) - это то, что может быть добавлено для версии 1.8, если естьдостаточно спроса (не забудьте проголосовать за Джира!).Это разумная дополнительная функция, которая откладывается только на количество времени, которое есть у разработчиков.Но я думаю, что это было бы отличным дополнением.

...