Шаблон Jackson + Builder?
Я бы хотел, чтобы Джексон десериализовал класс со следующим конструктором:
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?
Ответы
Ответ 1
Пока вы используете Jackson 2+, теперь есть встроенная поддержка для этого.
Сначала вам нужно добавить эту аннотацию в класс Address
:
@JsonDeserialize(builder = Address.Builder.class)
Затем вам нужно добавить эту аннотацию в класс Builder
:
@JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set")
Вы можете пропустить эту вторую аннотацию, если вы с удовольствием переименуете свой метод создания Builder для сборки, а ваши настройки Builder должны быть префиксными, а не заданы.
Полный пример:
@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();
}
}
Ответ 2
Ответ от @Rupert Madden-Abbott работает. Однако, если у вас есть конструктор, отличный от стандартного, например,
Builder(String city, String country) {...}
Затем вы должны аннотировать параметры, как показано ниже:
@JsonCreator
Builder(@JsonProperty("city") String city,
@JsonProperty("country") String country) {...}
Ответ 3
В результате я использовал @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();
}
}
Ответ 4
Решение, которое мне подходит в этом случае (я использовал аннотацию "Lombok").
@Getter
@Builder(builderMethodName = "builder")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.ANY,
creatorVisibility = JsonAutoDetect.Visibility.ANY
)
Надеюсь, тебе это тоже пригодится.
Ответ 5
В настоящее время нет поддержки для шаблона построителя, хотя он был запрошен довольно давно (и, наконец, был выпущен Jira issue http://jira.codehaus.org/browse/JACKSON-469) - это то, что может быть добавлено для выпуска 1.8, если есть достаточный спрос (обязательно проголосуйте в Jira!). Это разумная дополнительная функция, и только задержка с количеством разработчиков времени. Но я думаю, что это было бы отличным дополнением.
Ответ 6
У меня была очень похожая проблема при интеграции с Lombok. Потому что ломбок предоставляет аннотации для своего собственного застройщика.
https://www.thecuriousdev.org/lombok-builder-with-jackson/