diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/DefaultMapperReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/DefaultMapperReference.java index 924648368..6ac0c1c74 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/DefaultMapperReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/DefaultMapperReference.java @@ -21,19 +21,22 @@ import org.mapstruct.ap.internal.util.Strings; */ public class DefaultMapperReference extends MapperReference { + private final boolean isSingleton; private final boolean isAnnotatedMapper; private final Set importTypes; - private DefaultMapperReference(Type type, boolean isAnnotatedMapper, Set importTypes, String variableName) { + private DefaultMapperReference(Type type, boolean isAnnotatedMapper, boolean isSingleton, + Set importTypes, String variableName) { super( type, variableName ); this.isAnnotatedMapper = isAnnotatedMapper; this.importTypes = importTypes; + this.isSingleton = isSingleton; } - public static DefaultMapperReference getInstance(Type type, boolean isAnnotatedMapper, TypeFactory typeFactory, - List otherMapperReferences) { + public static DefaultMapperReference getInstance(Type type, boolean isAnnotatedMapper, boolean isSingleton, + TypeFactory typeFactory, List otherMapperReferences) { Set importTypes = Collections.asSet( type ); - if ( isAnnotatedMapper ) { + if ( isAnnotatedMapper && !isSingleton) { importTypes.add( typeFactory.getType( "org.mapstruct.factory.Mappers" ) ); } @@ -42,7 +45,7 @@ public class DefaultMapperReference extends MapperReference { otherMapperReferences ); - return new DefaultMapperReference( type, isAnnotatedMapper, importTypes, variableName ); + return new DefaultMapperReference( type, isAnnotatedMapper, isSingleton, importTypes, variableName ); } @Override @@ -53,4 +56,9 @@ public class DefaultMapperReference extends MapperReference { public boolean isAnnotatedMapper() { return isAnnotatedMapper; } + + public boolean isSingleton() { + return isSingleton; + } + } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java index a0014f593..ad6d84b9e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java @@ -6,6 +6,7 @@ package org.mapstruct.ap.internal.processor; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; @@ -13,7 +14,9 @@ import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -60,6 +63,9 @@ import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.version.VersionInformation; +import static javax.lang.model.element.Modifier.FINAL; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; import static org.mapstruct.ap.internal.model.SupportingConstructorFragment.addAllFragmentsIn; import static org.mapstruct.ap.internal.model.SupportingField.addAllFieldsIn; import static org.mapstruct.ap.internal.util.Collections.first; @@ -73,6 +79,9 @@ import static org.mapstruct.ap.internal.util.Collections.join; */ public class MapperCreationProcessor implements ModelElementProcessor, Mapper> { + /** Modifiers for public "constant" e.g. "public static final" */ + private static final List PUBLIC_CONSTANT_MODIFIERS = Arrays.asList( PUBLIC, STATIC, FINAL ); + private ElementUtils elementUtils; private TypeUtils typeUtils; private FormattingMessager messager; @@ -136,6 +145,7 @@ public class MapperCreationProcessor implements ModelElementProcessor isPublicConstantOfType( a, "INSTANCE", mapper ) ); + } + + /** + * @return true if the element is a "public static final" field (e.g. a constant) + * named fieldName of type "fieldType" + */ + private boolean isPublicConstantOfType(Element element, String fieldName, TypeMirror fieldType) { + return element.getKind().isField() && + element.getModifiers().containsAll( PUBLIC_CONSTANT_MODIFIERS ) && + element.getSimpleName().contentEquals( fieldName ) && + typeUtils.isSameType( element.asType(), fieldType ); + } + private Mapper getMapper(TypeElement element, MapperOptions mapperOptions, List methods) { List mappingMethods = getMappingMethods( mapperOptions, methods ); diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/DefaultMapperReference.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/DefaultMapperReference.ftl index e4eeddb4b..b2ab4cb6f 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/DefaultMapperReference.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/DefaultMapperReference.ftl @@ -6,4 +6,4 @@ --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.DefaultMapperReference" --> -private final <@includeModel object=type/> ${variableName} = <#if annotatedMapper>Mappers.getMapper( <@includeModel object=type/>.class );<#else>new <@includeModel object=type/>(); \ No newline at end of file +private final <@includeModel object=type/> ${variableName} = <#if singleton><@includeModel object=type/>.INSTANCE;<#else><#if annotatedMapper>Mappers.getMapper( <@includeModel object=type/>.class );<#else>new <@includeModel object=type/>(); \ No newline at end of file diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1Impl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1Impl.java index 7e53df87c..98f603d36 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1Impl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1Impl.java @@ -9,7 +9,6 @@ import javax.annotation.Generated; import org.mapstruct.ap.test.updatemethods.CompanyDto; import org.mapstruct.ap.test.updatemethods.CompanyEntity; import org.mapstruct.ap.test.updatemethods.DepartmentEntityFactory; -import org.mapstruct.factory.Mappers; @Generated( value = "org.mapstruct.ap.MappingProcessor", @@ -18,7 +17,7 @@ import org.mapstruct.factory.Mappers; ) public class OrganizationMapper1Impl implements OrganizationMapper1 { - private final ExternalMapper externalMapper = Mappers.getMapper( ExternalMapper.class ); + private final ExternalMapper externalMapper = ExternalMapper.INSTANCE; private final DepartmentEntityFactory departmentEntityFactory = new DepartmentEntityFactory(); @Override diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper3Impl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper3Impl.java index 11c3bd0df..76b2d3d9e 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper3Impl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper3Impl.java @@ -9,7 +9,6 @@ import javax.annotation.Generated; import org.mapstruct.ap.test.updatemethods.BossDto; import org.mapstruct.ap.test.updatemethods.BossEntity; import org.mapstruct.ap.test.updatemethods.ConstructableDepartmentEntity; -import org.mapstruct.factory.Mappers; @Generated( value = "org.mapstruct.ap.MappingProcessor", @@ -18,7 +17,7 @@ import org.mapstruct.factory.Mappers; ) public class OrganizationMapper3Impl implements OrganizationMapper3 { - private final ExternalMapper externalMapper = Mappers.getMapper( ExternalMapper.class ); + private final ExternalMapper externalMapper = ExternalMapper.INSTANCE; @Override public void toBossEntity(BossDto dto, BossEntity entity) {