#2277 default component model: mapper reference use singleton INSTANCE if it exists (#2280)

This allows to easily avoid the runtime dependency on mapstruct.jar:
we can avoid Mappers.getMapper(...) for instantiating used mappers if
the code follows the conventional pattern for creating mapper singletons.

Co-authored-by: GIBOU Damien <damien.gibou@biomerieux.com>
This commit is contained in:
dmngb 2021-02-06 16:10:32 +01:00 committed by GitHub
parent aeadf8cb77
commit c59ca79e7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 10 deletions

View File

@ -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<Type> importTypes;
private DefaultMapperReference(Type type, boolean isAnnotatedMapper, Set<Type> importTypes, String variableName) {
private DefaultMapperReference(Type type, boolean isAnnotatedMapper, boolean isSingleton,
Set<Type> 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<String> otherMapperReferences) {
public static DefaultMapperReference getInstance(Type type, boolean isAnnotatedMapper, boolean isSingleton,
TypeFactory typeFactory, List<String> otherMapperReferences) {
Set<Type> 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;
}
}

View File

@ -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<List<SourceMethod>, Mapper> {
/** Modifiers for public "constant" e.g. "public static final" */
private static final List<Modifier> 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<List<Sourc
DefaultMapperReference mapperReference = DefaultMapperReference.getInstance(
typeFactory.getType( usedMapper ),
MapperGem.instanceOn( typeUtils.asElement( usedMapper ) ) != null,
hasSingletonInstance( usedMapper ),
typeFactory,
variableNames
);
@ -147,6 +157,22 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
return result;
}
private boolean hasSingletonInstance(TypeMirror mapper) {
return typeUtils.asElement( mapper ).getEnclosedElements().stream()
.anyMatch( a -> isPublicConstantOfType( a, "INSTANCE", mapper ) );
}
/**
* @return true if the <code>element</code> is a "public static final" field (e.g. a constant)
* named <code>fieldName</code> 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<SourceMethod> methods) {
List<MappingMethod> mappingMethods = getMappingMethods( mapperOptions, methods );

View File

@ -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/>();</#if>
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/>();</#if></#if>

View File

@ -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

View File

@ -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) {