diff --git a/core/src/main/java/org/mapstruct/factory/Mappers.java b/core/src/main/java/org/mapstruct/factory/Mappers.java index 05b616fe9a..464c5f095d 100644 --- a/core/src/main/java/org/mapstruct/factory/Mappers.java +++ b/core/src/main/java/org/mapstruct/factory/Mappers.java @@ -8,6 +8,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.ServiceLoader; @@ -75,14 +76,21 @@ private static T getMapper(Class mapperType, Iterable classL throw new ClassNotFoundException("Cannot find implementation for " + mapperType.getName() ); } - private static T doGetMapper(Class clazz, ClassLoader classLoader) throws NoSuchMethodException { + private static T doGetMapper(Class clazz, ClassLoader classLoader) { try { @SuppressWarnings( "unchecked" ) Class implementation = (Class) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ); - Constructor constructor = implementation.getDeclaredConstructor(); - constructor.setAccessible( true ); - return constructor.newInstance(); + Constructor[] constructors = implementation.getDeclaredConstructors(); + Constructor constructor = (Constructor) constructors[0]; + constructor.setAccessible(true); + // the parameters are mappers + Class[] parameters = constructor.getParameterTypes(); + Object[] args = Arrays.stream(parameters) + .map(paramClass -> doGetMapper(paramClass, classLoader)) + .toArray(); + + return constructor.newInstance(args); } catch (ClassNotFoundException e) { return getMapperFromServiceLoader( clazz, classLoader ); diff --git a/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsed.java b/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsed.java new file mode 100644 index 0000000000..e643474f39 --- /dev/null +++ b/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsed.java @@ -0,0 +1,17 @@ +package org.mapstruct.factory; + +import org.mapstruct.Mapper; + +@Mapper +public interface MapperWhichIsUsed { + + Foo toModel(FooDto dto); + + class Foo { + public String name; + } + + class FooDto { + public String name; + } +} diff --git a/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsedImpl.java b/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsedImpl.java new file mode 100644 index 0000000000..acb7502fac --- /dev/null +++ b/core/src/test/java/org/mapstruct/factory/MapperWhichIsUsedImpl.java @@ -0,0 +1,15 @@ +package org.mapstruct.factory; + +class MapperWhichIsUsedImpl implements MapperWhichIsUsed { + + @Override + public Foo toModel(MapperWhichIsUsed.FooDto dto) { + if ( dto == null ) { + return null; + } + + Foo foo = new Foo(); + + return foo; + } +} diff --git a/core/src/test/java/org/mapstruct/factory/MapperWithUses.java b/core/src/test/java/org/mapstruct/factory/MapperWithUses.java new file mode 100644 index 0000000000..6fd5f11c1a --- /dev/null +++ b/core/src/test/java/org/mapstruct/factory/MapperWithUses.java @@ -0,0 +1,40 @@ +package org.mapstruct.factory; + +import org.mapstruct.InjectionStrategy; +import org.mapstruct.Mapper; + +@Mapper( + uses = MapperWhichIsUsed.class, + injectionStrategy = InjectionStrategy.CONSTRUCTOR +) +public interface MapperWithUses { + Bar toModel(BarDto dto); + + class Bar { + private final String name; + private final MapperWhichIsUsed.Foo foo; + + public Bar(String name, MapperWhichIsUsed.Foo foo) { + this.name = name; + this.foo = foo; + } + } + + class BarDto { + private final String name; + private final MapperWhichIsUsed.FooDto foo; + + BarDto(String name, MapperWhichIsUsed.FooDto foo) { + this.name = name; + this.foo = foo; + } + + public String getName() { + return this.name; + } + + public MapperWhichIsUsed.FooDto getFoo() { + return this.foo; + } + } +} diff --git a/core/src/test/java/org/mapstruct/factory/MapperWithUsesImpl.java b/core/src/test/java/org/mapstruct/factory/MapperWithUsesImpl.java new file mode 100644 index 0000000000..faeb781011 --- /dev/null +++ b/core/src/test/java/org/mapstruct/factory/MapperWithUsesImpl.java @@ -0,0 +1,27 @@ +package org.mapstruct.factory; + +public class MapperWithUsesImpl implements MapperWithUses { + + private final MapperWhichIsUsed mapperWhichIsUsed; + + public MapperWithUsesImpl(MapperWhichIsUsed mapperWhichIsUsed) { + this.mapperWhichIsUsed = mapperWhichIsUsed; + } + + @Override + public Bar toModel(BarDto dto) { + if (dto == null) { + return null; + } + + String name = null; + MapperWhichIsUsed.Foo foo = null; + + name = dto.getName(); + foo = mapperWhichIsUsed.toModel(dto.getFoo()); + + Bar bar = new Bar(name, foo); + + return bar; + } +} diff --git a/core/src/test/java/org/mapstruct/factory/MappersTest.java b/core/src/test/java/org/mapstruct/factory/MappersTest.java index 6118ba09cb..60600cb078 100644 --- a/core/src/test/java/org/mapstruct/factory/MappersTest.java +++ b/core/src/test/java/org/mapstruct/factory/MappersTest.java @@ -58,4 +58,9 @@ public void shouldReturnPackagePrivateImplementationInstance() { public void shouldReturnPackagePrivateImplementationClass() { assertThat( Mappers.getMapperClass( PackagePrivateMapper.class ) ).isNotNull(); } + + @Test + public void shouldReturnImplementationClassOfMapperWhichDependsOnAnotherOnes() { + assertThat( Mappers.getMapper( MapperWithUses.class ) ).isNotNull(); + } }