Джексон поддерживает Optional
, используя его jackson-datatype-jdk8
модуль. Вы можете просто добавить его в раздел <dependencies>
в вашем pom.xml
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.10.3</version>
</dependency>
Затем инициализируйте свой маппер следующим образом:
ObjectMapper mapper = new XmlMapper().registerModule(new Jdk8Module());
Этот маппер автоматически обнаружит Optional
s: Если поле XML имеет значение, оно будет заключено в Optional
; если поле XML пустое (т. е. <DETAIL_TRAIN/>
), то результатом будет Optional.empty()
. (В вашем случае у вас есть атрибут; он не может быть пустым.)
Джексон отображает поля или атрибуты, которые не существуют в XML на null
(или, точнее, он просто не вызывает установщик, поэтому значение поля все равно будет значением по умолчанию). Если вы также хотите, чтобы в этом случае был пустой Optional
, вам нужно установить для поля по умолчанию значение Optional.empty()
и добавить к этому полю @Builder.Default
.
Наконец, lombok может автоматически копировать ваши аннотации от полей до созданного строителя. Вы должны указать lombok, какие аннотации копировать, используя lombok.config
файл в вашем проекте root, содержащий:
lombok.copyableAnnotations += com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
config.stopBubbling = true
Это означает, что вам вообще не нужно настраивать свой класс построителя:
@JsonDeserialize(builder = AvailabilityResponse.Builder.class)
@Getter
@ToString
@EqualsAndHashCode
@Builder(setterPrefix = "with", builderClassName = "Builder", toBuilder = true)
public class AvailabilityResponse {
@JacksonXmlProperty(localName = "TRAIN")
@JsonProperty("TRAIN")
private final List<Train> trainDetails;
@JacksonXmlProperty(localName = "NAME")
@JsonProperty("NAME")
private final String name;
@JacksonXmlProperty(localName = "DETAIL_TRAIN", isAttribute = true)
@JsonProperty("DETAIL_TRAIN")
@Builder.Default
private final Optional<String> detail = Optional.empty();
}
Обратите внимание, что вам также нужно @JsonProperty
аннотаций к вашим полям из-за ошибки Джексона .
Если вы хотите проверить значения полей, вы должны сделать это в конструкторе не в строителе. Таким образом, вы также поймете те экземпляры, где строитель не используется. Для этого просто внедрите конструктор all-args самостоятельно; метод build()
будет использовать его автоматически:
private AvailabilityResponse(List<Train> trainDetails, String name, Optional<String> detail) {
this.trainDetails = Objects.requireNonNull(trainDetails);
this.name = Objects.requireNonNull(name);
this.detail = Objects.requireNonNull(detail);
}
Я предлагаю сделать этот конструктор private
, потому что
- заставляет пользователей вашего класса использовать конструктор, и
- плохой стиль иметь
Optional
s в качестве параметров в вашем API Publi c.