Мы используем immutables framework для генерации всех DTO. Теперь мы хотим сопоставить эти объекты друг другу с помощью mapstruct. Но сгенерированные DTO неизменяемы и не имеют сеттеров и никакого конструктора, соответствующего шаблону строителя. Они заполняются только через соответствующий строитель, к которому обращается статический метод builder()
.Сопоставление объекта с неизменяемым объектом с помощью построителя (с использованием обработчика аннотаций неизменяемости) в mapstruct
Вместо этого мы попытались отобразить DTO1 в DTO2.Builder, который будет работать, если mapstruct будет распознавать setter в Builder, но они не имеют типа возвращаемого типа, но возвращают сам Builder для свободного конкатенации.
Так вот код примера.
У нас есть два интерфейса
@Value.Immutable
public interface MammalDto {
public Integer getNumberOfLegs();
public Long getNumberOfStomachs();
}
и
@Value.Immutable
public interface MammalEntity {
public Long getNumberOfLegs();
public Long getNumberOfStomachs();
}
Тогда мы имеем интерфейс Mapper для mapstruct:
@Mapper(uses = ObjectFactory.class)
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);
ImmutableMammalEntity.Builder toTarget(MammalDto source);
}
Для mapstruct найти Строителя нам нужен завод:
public class ObjectFactory {
public ImmutableMammalDto.Builder createMammalDto() {
return ImmutableMammalDto.builder();
}
public ImmutableMammalEntity.Builder createMammalEntity() {
return ImmutableMammalEntity.builder();
}
}
Для того, чтобы сгенерировать код плагин компилятора был проинструктирован использовать оба аннотаций процессора:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.immutables</groupId>
<artifactId>value</artifactId>
<version>2.2.8</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Beta3</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Примечание: Это будет работать только с mapstruct версия> 1.2.x. У старых версий есть проблема в чистой сборке (mvn clean compile
), что они не могут найти источники, которые только что построили. Во второй сборке (без очистки) они найдут реализацию immutables, потому что они находились в пути к классам до запуска обработчиков аннотаций. Эта ошибка исправлена.
Это работает как шарм. Сначала генерируются Неизменяемые реализации межфактур, а mapstruct использует их для создания строителя.
Но тест показывает, что никакие свойства не установлены:
@Test
public void test() {
MammalDto s = ImmutableMammalDto.builder().numberOfLegs(4).numberOfStomachs(3l).build();
MammalEntity t = SourceTargetMapper.MAPPER.toTarget(s).build();
assertThat(t.getNumberOfLegs()).isEqualTo(4);
assertThat(t.getNumberOfStomachs()).isEqualTo(3);
}
утверждает неудачу. Один взгляд на картографа, порожденного mapstruct показывает, что он явно не нашел каких-либо сеттеры:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
//...
)
public class SourceTargetMapperImpl implements SourceTargetMapper {
private final ObjectFactory objectFactory = new ObjectFactory();
@Override
public Builder toTarget(MammalDto source) {
if (source == null) {
return null;
}
Builder builder = objectFactory.createMammalEntity();
return builder;
}
}
Пустое строитель возвращается. Я думаю, что причина заключается в сеттер реализации вырабатываемого строителя, потому что она возвращает себя, чтобы создать свободно API:
public final Builder numberOfLegs(Long numberOfLegs) {
this.numberOfLegs = Objects.requireNonNull(numberOfLegs, "numberOfLegs");
return this;
}
Есть ли способ, чтобы позволить mapstruct найти эти сеттер? Или даже лучший способ справиться с такими непреложными объектами со строителями?
EDIT: Как я уже говорил в комментарии, я столкнулся с Issue #782. В версии 1.2.0.Beta3 сборщики по-прежнему не поддерживаются. Но есть несколько дискуссий по этой теме, поэтому было бы интересно следить за проблемой, если у вас есть одна и та же проблема.
Как заявил Андреас Gudian я столкнулся с известной проблемой. Запрос функции № 782 «Сопоставление неизменяемых объектов с строителями» открыт с версии 1.1.0.Beta2. Расширение можно найти в интеграционном тестовом модуле mapstruct. Я буду адаптировать этот экстракт к конкретным потребностям на следующей итерации. Любые предложения по конкретному внедрению приветствуются. Java-Model-API кажется немного сложным ... –