Używamy immutables framework do generowania wszystkich DTO. Teraz chcielibyśmy odwzorować te obiekty jeden na drugi z mapstruct. Jednak wygenerowane DTO są niezmienne i nie mają ustawników ani konstruktora, co odpowiada wzorowi budowniczego. Są one wypełniane tylko przez odpowiedni program budujący, do którego dostęp ma statyczna metoda.Mapowanie obiektu na niezmienny obiekt za pomocą konstruktora (za pomocą procesora adnotacji niezmiennych) w mapstruct
Zamiast tego próbowaliśmy odwzorować DTO1 na DTO2.Builder, który zadziałałby, gdyby system mapctct rozpoznał narzędzie ustawiające w Builderze, ale nie ma on pustego typu zwracania, ale zwraca Builderowi w celu płynnej konkatenacji.
Oto kod przykładu.
Mamy dwa interfejsy
@Value.Immutable
public interface MammalDto {
public Integer getNumberOfLegs();
public Long getNumberOfStomachs();
}
i
@Value.Immutable
public interface MammalEntity {
public Long getNumberOfLegs();
public Long getNumberOfStomachs();
}
Następnie mamy interfejs Mapper dla mapstruct:
@Mapper(uses = ObjectFactory.class)
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);
ImmutableMammalEntity.Builder toTarget(MammalDto source);
}
Dla mapstruct znalezienia Builder musimy fabryczne:
public class ObjectFactory {
public ImmutableMammalDto.Builder createMammalDto() {
return ImmutableMammalDto.builder();
}
public ImmutableMammalEntity.Builder createMammalEntity() {
return ImmutableMammalEntity.builder();
}
}
W celu wygenerowania kodu wtyczki kompilatora został poinstruowany, aby korzystać z obu procesorów dopiskiem
<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>
Uwaga: to będzie działać tylko z wersji mapstruct> 1.2.x. Starsze wersje mają problem z czystą kompilacją (mvn clean compile
), że nie znajdują źródeł, które tylko wbudowane zostały niezmienione. W drugiej wersji (bez czystej) znajdziemy implementacje immutables, ponieważ znajdują się one w ścieżce klas przed uruchomieniem procesorów adnotacji. Ten błąd został naprawiony teraz.
Działa to jak urok. Najpierw generowane są Niezmienne implementacje interfactes i mapstruct używa ich do generowania budowniczego.
ale test pokazuje, że nie ma właściwości są ustawione:
@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);
}
twierdzi niepowodzeniem. Jedno spojrzenie na odwzorowującego generowanego przez mapstruct pokazuje, że to oczywiście nie znaleziono żadnych ustawiające:
@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;
}
}
Pusty budowniczy jest zwracana. Myślę, że powodem jest seter realizacja wygenerowanego konstruktora, ponieważ zwraca się do stworzenia biegle API:
public final Builder numberOfLegs(Long numberOfLegs) {
this.numberOfLegs = Objects.requireNonNull(numberOfLegs, "numberOfLegs");
return this;
}
Czy istnieje sposób, aby pozwolić mapstruct znaleźć te ustawiające? A może nawet lepszy sposób radzenia sobie z takimi niezmiennymi obiektami z budowniczymi?
EDYCJA: Jak stwierdziłem w komentarzu wpadłem na Issue #782. W wersji 1.2.0. Builder beta 3 nadal nie jest obsługiwany. Ale jest kilka dyskusji na ten temat, więc może być interesujące śledzenie problemu, jeśli ma się ten sam problem.
jak stwierdził Andreas Gudian Pobiegłem do znanego problemu. Żądanie funkcji # 782 "Mapowanie niezmiennych obiektów za pomocą Builderów" jest otwarte od wersji 1.1.0.Beta2. Przykład można znaleźć w module testowym integracji programu mapstruct. Będę dostosowywać ten ekwipunek do konkretnych potrzeb w następnej iteracji. Wszelkie sugestie dotyczące konkretnej implementacji są mile widziane. Model Java-Model-API wydaje się być nieco trudny ... –