From 8a247060263fabbf1c271d1c1462acb8a3645efc Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 22 Apr 2018 09:59:20 +0200 Subject: [PATCH] Extract methods that use the AccessorNamingStrategy into class instance methods This helps towards #1415, where we need to use strategy based on presence / absence of Immutables --- .../internal/model/MappingBuilderContext.java | 8 ++ .../ap/internal/model/PropertyMapping.java | 17 +-- .../ap/internal/model/common/Type.java | 40 +++--- .../ap/internal/model/common/TypeFactory.java | 2 + .../ap/internal/model/source/Mapping.java | 17 ++- .../internal/model/source/MappingOptions.java | 11 +- .../internal/model/source/SourceMethod.java | 9 +- .../model/source/TargetReference.java | 11 +- .../DefaultModelElementProcessorContext.java | 8 ++ .../processor/MapperCreationProcessor.java | 38 ++++- .../processor/MethodRetrievalProcessor.java | 5 + .../processor/ModelElementProcessor.java | 3 + .../ap/internal/util/AccessorNamingUtils.java | 132 ++++++++++++++++++ .../util/AnnotationProcessorContext.java | 6 + .../ap/internal/util/Executables.java | 92 +----------- .../mapstruct/ap/internal/util/Filters.java | 17 +-- .../DateFormatValidatorFactoryTest.java | 1 + .../common/DefaultConversionContextTest.java | 1 + 18 files changed, 278 insertions(+), 140 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/internal/util/AccessorNamingUtils.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java index 77bca9fcf..b8449d975 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java @@ -38,6 +38,7 @@ import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.SourceMethod; import org.mapstruct.ap.internal.option.Options; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Services; import org.mapstruct.ap.spi.MappingExclusionProvider; @@ -125,6 +126,7 @@ public class MappingBuilderContext { private final Elements elementUtils; private final Types typeUtils; private final FormattingMessager messager; + private final AccessorNamingUtils accessorNaming; private final Options options; private final TypeElement mapperTypeElement; private final List sourceModel; @@ -138,6 +140,7 @@ public class MappingBuilderContext { Elements elementUtils, Types typeUtils, FormattingMessager messager, + AccessorNamingUtils accessorNaming, Options options, MappingResolver mappingResolver, TypeElement mapper, @@ -147,6 +150,7 @@ public class MappingBuilderContext { this.elementUtils = elementUtils; this.typeUtils = typeUtils; this.messager = messager; + this.accessorNaming = accessorNaming; this.options = options; this.mappingResolver = mappingResolver; this.mapperTypeElement = mapper; @@ -195,6 +199,10 @@ public class MappingBuilderContext { return messager; } + public AccessorNamingUtils getAccessorNaming() { + return accessorNaming; + } + public Options getOptions() { return options; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java index cb48c23d5..14f1d1153 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java @@ -50,6 +50,7 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.SourceReference; import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism; import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.Executables; import org.mapstruct.ap.internal.util.MapperConfiguration; import org.mapstruct.ap.internal.util.Message; @@ -86,14 +87,14 @@ public class PropertyMapping extends ModelElement { SETTER, ADDER; - public static TargetWriteAccessorType of(Accessor accessor) { - if ( Executables.isSetterMethod( accessor ) ) { + public static TargetWriteAccessorType of(AccessorNamingUtils accessorNaming, Accessor accessor) { + if ( accessorNaming.isSetterMethod( accessor ) ) { return TargetWriteAccessorType.SETTER; } - else if ( Executables.isAdderMethod( accessor ) ) { + else if ( accessorNaming.isAdderMethod( accessor ) ) { return TargetWriteAccessorType.ADDER; } - else if ( Executables.isGetterMethod( accessor ) ) { + else if ( accessorNaming.isGetterMethod( accessor ) ) { return TargetWriteAccessorType.GETTER; } else { @@ -131,7 +132,7 @@ public class PropertyMapping extends ModelElement { this.targetReadAccessor = targetProp.getReadAccessor(); this.targetWriteAccessor = targetProp.getWriteAccessor(); this.targetType = targetProp.getType(); - this.targetWriteAccessorType = TargetWriteAccessorType.of( targetWriteAccessor ); + this.targetWriteAccessorType = TargetWriteAccessorType.of( ctx.getAccessorNaming(), targetWriteAccessor ); return (T) this; } @@ -142,7 +143,7 @@ public class PropertyMapping extends ModelElement { public T targetWriteAccessor(Accessor targetWriteAccessor) { this.targetWriteAccessor = targetWriteAccessor; - this.targetWriteAccessorType = TargetWriteAccessorType.of( targetWriteAccessor ); + this.targetWriteAccessorType = TargetWriteAccessorType.of( ctx.getAccessorNaming(), targetWriteAccessor ); this.targetType = determineTargetType(); return (T) this; @@ -785,7 +786,7 @@ public class PropertyMapping extends ModelElement { if ( assignment != null ) { - if ( Executables.isSetterMethod( targetWriteAccessor ) || + if ( ctx.getAccessorNaming().isSetterMethod( targetWriteAccessor ) || Executables.isFieldAccessor( targetWriteAccessor ) ) { // target accessor is setter, so decorate assignment as setter @@ -883,7 +884,7 @@ public class PropertyMapping extends ModelElement { public PropertyMapping build() { Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames, "" ); - if ( Executables.isSetterMethod( targetWriteAccessor ) || + if ( ctx.getAccessorNaming().isSetterMethod( targetWriteAccessor ) || Executables.isFieldAccessor( targetWriteAccessor ) ) { // setter, so wrap in setter assignment = new SetterWrapper( assignment, method.getThrownTypes(), isFieldAssignment() ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index 1ae66dbe7..0b27f771e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -44,6 +44,7 @@ import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.Executables; import org.mapstruct.ap.internal.util.Filters; import org.mapstruct.ap.internal.util.Nouns; @@ -68,6 +69,7 @@ public class Type extends ModelElement implements Comparable { private final Types typeUtils; private final Elements elementUtils; private final TypeFactory typeFactory; + private final AccessorNamingUtils accessorNaming; private final TypeMirror typeMirror; private final TypeElement typeElement; @@ -108,6 +110,7 @@ public class Type extends ModelElement implements Comparable { //CHECKSTYLE:OFF public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory, + AccessorNamingUtils accessorNaming, TypeMirror typeMirror, TypeElement typeElement, List typeParameters, ImplementationType implementationType, Type componentType, BuilderInfo builderInfo, @@ -119,6 +122,7 @@ public class Type extends ModelElement implements Comparable { this.typeUtils = typeUtils; this.elementUtils = elementUtils; this.typeFactory = typeFactory; + this.accessorNaming = accessorNaming; this.typeMirror = typeMirror; this.typeElement = typeElement; @@ -374,6 +378,7 @@ public class Type extends ModelElement implements Comparable { typeUtils, elementUtils, typeFactory, + accessorNaming, typeUtils.erasure( typeMirror ), typeElement, typeParameters, @@ -421,26 +426,26 @@ public class Type extends ModelElement implements Comparable { */ public Map getPropertyReadAccessors() { if ( readAccessors == null ) { - List getterList = Filters.getterMethodsIn( getAllAccessors() ); + List getterList = Filters.getterMethodsIn( accessorNaming, getAllAccessors() ); Map modifiableGetters = new LinkedHashMap(); for ( Accessor getter : getterList ) { - String propertyName = Executables.getPropertyName( getter ); + String propertyName = accessorNaming.getPropertyName( getter ); if ( modifiableGetters.containsKey( propertyName ) ) { // In the DefaultAccessorNamingStrategy, this can only be the case for Booleans: isFoo() and // getFoo(); The latter is preferred. if ( !getter.getSimpleName().toString().startsWith( "is" ) ) { - modifiableGetters.put( Executables.getPropertyName( getter ), getter ); + modifiableGetters.put( accessorNaming.getPropertyName( getter ), getter ); } } else { - modifiableGetters.put( Executables.getPropertyName( getter ), getter ); + modifiableGetters.put( accessorNaming.getPropertyName( getter ), getter ); } } List fieldsList = Filters.fieldsIn( getAllAccessors() ); for ( Accessor field : fieldsList ) { - String propertyName = Executables.getPropertyName( field ); + String propertyName = accessorNaming.getPropertyName( field ); if ( !modifiableGetters.containsKey( propertyName ) ) { // If there was no getter or is method for booleans, then resort to the field. // If a field was already added do not add it again. @@ -459,11 +464,14 @@ public class Type extends ModelElement implements Comparable { */ public Map getPropertyPresenceCheckers() { if ( presenceCheckers == null ) { - List checkerList = Filters.presenceCheckMethodsIn( getAllAccessors() ); + List checkerList = Filters.presenceCheckMethodsIn( + accessorNaming, + getAllAccessors() + ); Map modifiableCheckers = new LinkedHashMap(); for ( ExecutableElementAccessor checker : checkerList ) { - modifiableCheckers.put( Executables.getPropertyName( checker ), checker ); + modifiableCheckers.put( accessorNaming.getPropertyName( checker ), checker ); } presenceCheckers = Collections.unmodifiableMap( modifiableCheckers ); } @@ -491,7 +499,7 @@ public class Type extends ModelElement implements Comparable { Map result = new LinkedHashMap(); for ( Accessor candidate : candidates ) { - String targetPropertyName = Executables.getPropertyName( candidate ); + String targetPropertyName = accessorNaming.getPropertyName( candidate ); Accessor readAccessor = getPropertyReadAccessors().get( targetPropertyName ); @@ -507,12 +515,12 @@ public class Type extends ModelElement implements Comparable { // first check if there's a setter method. Accessor adderMethod = null; - if ( Executables.isSetterMethod( candidate ) + if ( accessorNaming.isSetterMethod( candidate ) // ok, the current accessor is a setter. So now the strategy determines what to use && cmStrategy == CollectionMappingStrategyPrism.ADDER_PREFERRED ) { adderMethod = getAdderForType( targetType, targetPropertyName ); } - else if ( Executables.isGetterMethod( candidate ) ) { + else if ( accessorNaming.isGetterMethod( candidate ) ) { // the current accessor is a getter (no setter available). But still, an add method is according // to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter. adderMethod = getAdderForType( targetType, targetPropertyName ); @@ -550,7 +558,7 @@ public class Type extends ModelElement implements Comparable { if ( parameter != null ) { return parameter.getType(); } - else if ( Executables.isGetterMethod( candidate ) || Executables.isFieldAccessor( candidate ) ) { + else if ( accessorNaming.isGetterMethod( candidate ) || Executables.isFieldAccessor( candidate ) ) { return typeFactory.getReturnType( (DeclaredType) typeMirror, candidate ); } return null; @@ -613,7 +621,7 @@ public class Type extends ModelElement implements Comparable { } else { for ( Accessor candidate : candidates ) { - String elementName = Executables.getElementNameForAdder( candidate ); + String elementName = accessorNaming.getElementNameForAdder( candidate ); if ( elementName != null && elementName.equals( Nouns.singularize( pluralPropertyName ) ) ) { return candidate; } @@ -630,7 +638,7 @@ public class Type extends ModelElement implements Comparable { */ private List getSetters() { if ( setters == null ) { - setters = Collections.unmodifiableList( Filters.setterMethodsIn( getAllAccessors() ) ); + setters = Collections.unmodifiableList( Filters.setterMethodsIn( accessorNaming, getAllAccessors() ) ); } return setters; } @@ -645,7 +653,7 @@ public class Type extends ModelElement implements Comparable { */ private List getAdders() { if ( adders == null ) { - adders = Collections.unmodifiableList( Filters.adderMethodsIn( getAllAccessors() ) ); + adders = Collections.unmodifiableList( Filters.adderMethodsIn( accessorNaming, getAllAccessors() ) ); } return adders; } @@ -691,10 +699,10 @@ public class Type extends ModelElement implements Comparable { private boolean correspondingSetterMethodExists(Accessor getterMethod, List setterMethods) { - String getterPropertyName = Executables.getPropertyName( getterMethod ); + String getterPropertyName = accessorNaming.getPropertyName( getterMethod ); for ( Accessor setterMethod : setterMethods ) { - String setterPropertyName = Executables.getPropertyName( setterMethod ); + String setterPropertyName = accessorNaming.getPropertyName( setterMethod ); if ( getterPropertyName.equals( setterPropertyName ) ) { return true; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java index d540cfcb2..8b87f92ef 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java @@ -289,6 +289,7 @@ public class TypeFactory { return new Type( typeUtils, elementUtils, this, + roundContext.getAnnotationProcessorContext().getAccessorNaming(), mirror, typeElement, getTypeParameters( mirror, false ), @@ -500,6 +501,7 @@ public class TypeFactory { typeUtils, elementUtils, this, + roundContext.getAnnotationProcessorContext().getAccessorNaming(), typeUtils.getDeclaredType( implementationType.getTypeElement(), declaredType.getTypeArguments().toArray( new TypeMirror[] { } ) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java index fb840d659..7f695b386 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java @@ -39,6 +39,7 @@ import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.prism.MappingPrism; import org.mapstruct.ap.internal.prism.MappingsPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Strings; @@ -333,8 +334,9 @@ public class Mapping { ( (DeclaredType) mirror ).asElement().getKind() == ElementKind.ENUM; } - public void init(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory) { - init( method, messager, typeFactory, false, null ); + public void init(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory, + AccessorNamingUtils accessorNaming) { + init( method, messager, typeFactory, accessorNaming, false, null ); } /** @@ -343,11 +345,13 @@ public class Mapping { * @param method the source method that the mapping belongs to * @param messager the messager that can be used for outputting messages * @param typeFactory the type factory + * @param accessorNaming the accessor naming utils * @param isReverse whether the init is for a reverse mapping * @param reverseSourceParameter the source parameter from the revers mapping */ - private void init(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory, boolean isReverse, - Parameter reverseSourceParameter) { + private void init(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory, + AccessorNamingUtils accessorNaming, boolean isReverse, + Parameter reverseSourceParameter) { if ( !method.isEnumMapping() ) { sourceReference = new SourceReference.BuilderFromMapping() @@ -363,6 +367,7 @@ public class Mapping { .method( method ) .messager( messager ) .typeFactory( typeFactory ) + .accessorNaming( accessorNaming ) .reverseSourceParameter( reverseSourceParameter ) .build(); } @@ -473,7 +478,8 @@ public class Mapping { return dependsOn; } - public Mapping reverse(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory) { + public Mapping reverse(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory, + AccessorNamingUtils accessorNaming) { // mapping can only be reversed if the source was not a constant nor an expression nor a nested property // and the mapping is not a 'target-source-ignore' mapping @@ -502,6 +508,7 @@ public class Mapping { method, messager, typeFactory, + accessorNaming, true, sourceReference != null ? sourceReference.getParameter() : null ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java index 2b4c1b518..62cb0dd3d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java @@ -33,6 +33,7 @@ import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.accessor.Accessor; @@ -220,9 +221,11 @@ public class MappingOptions { * @param method the source method * @param messager the messager * @param typeFactory the type factory + * @param accessorNaming the accessor naming utils */ public void applyInheritedOptions(MappingOptions inherited, boolean isInverse, SourceMethod method, - FormattingMessager messager, TypeFactory typeFactory) { + FormattingMessager messager, TypeFactory typeFactory, + AccessorNamingUtils accessorNaming) { if ( null != inherited ) { if ( getIterableMapping() == null ) { if ( inherited.getIterableMapping() != null ) { @@ -270,7 +273,7 @@ public class MappingOptions { for ( List lmappings : inherited.getMappings().values() ) { for ( Mapping mapping : lmappings ) { if ( isInverse ) { - mapping = mapping.reverse( method, messager, typeFactory ); + mapping = mapping.reverse( method, messager, typeFactory, accessorNaming ); } if ( mapping != null ) { @@ -297,7 +300,7 @@ public class MappingOptions { } public void applyIgnoreAll(MappingOptions inherited, SourceMethod method, FormattingMessager messager, - TypeFactory typeFactory ) { + TypeFactory typeFactory, AccessorNamingUtils accessorNaming) { CollectionMappingStrategyPrism cms = method.getMapperConfiguration().getCollectionMappingStrategy(); Type writeType = method.getResultType(); if ( !method.isUpdateMethod() ) { @@ -311,7 +314,7 @@ public class MappingOptions { for ( String targetPropertyName : writeAccessors.keySet() ) { if ( !mappedPropertyNames.contains( targetPropertyName ) ) { Mapping mapping = Mapping.forIgnore( targetPropertyName ); - mapping.init( method, messager, typeFactory ); + mapping.init( method, messager, typeFactory, accessorNaming ); mappings.put( targetPropertyName, Arrays.asList( mapping ) ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceMethod.java index e678a4372..4cf01354d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceMethod.java @@ -36,6 +36,7 @@ import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.prism.ObjectFactoryPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.Executables; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.MapperConfiguration; @@ -99,6 +100,7 @@ public class SourceMethod implements Method { private BeanMapping beanMapping = null; private Types typeUtils; private TypeFactory typeFactory = null; + private AccessorNamingUtils accessorNaming = null; private FormattingMessager messager = null; private MapperConfiguration mapperConfig = null; private List prototypeMethods = Collections.emptyList(); @@ -165,6 +167,11 @@ public class SourceMethod implements Method { return this; } + public Builder setAccessorNaming(AccessorNamingUtils accessorNaming) { + this.accessorNaming = accessorNaming; + return this; + } + public Builder setMessager(FormattingMessager messager) { this.messager = messager; return this; @@ -200,7 +207,7 @@ public class SourceMethod implements Method { if ( mappings != null ) { for ( Map.Entry> entry : mappings.entrySet() ) { for ( Mapping mapping : entry.getValue() ) { - mapping.init( sourceMethod, messager, typeFactory ); + mapping.init( sourceMethod, messager, typeFactory, accessorNaming ); } } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java index 5b48d54cc..327b7a290 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java @@ -30,6 +30,7 @@ import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.Executables; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Message; @@ -74,6 +75,7 @@ public class TargetReference { private SourceMethod method; private FormattingMessager messager; private TypeFactory typeFactory; + private AccessorNamingUtils accessorNaming; private boolean isReverse; /** * Needed when we are building from reverse mapping. It is needed, so we can remove the first level if it is @@ -119,6 +121,11 @@ public class TargetReference { return this; } + public BuilderFromTargetMapping accessorNaming(AccessorNamingUtils accessorNaming) { + this.accessorNaming = accessorNaming; + return this; + } + public BuilderFromTargetMapping isReverse(boolean isReverse) { this.isReverse = isReverse; return this; @@ -204,7 +211,7 @@ public class TargetReference { break; } - if ( isLast || ( Executables.isSetterMethod( targetWriteAccessor ) + if ( isLast || ( accessorNaming.isSetterMethod( targetWriteAccessor ) || Executables.isFieldAccessor( targetWriteAccessor ) ) ) { // only intermediate nested properties when they are a true setter or field accessor // the last may be other readAccessor (setter / getter / adder). @@ -234,7 +241,7 @@ public class TargetReference { private Type findNextType(Type initial, Accessor targetWriteAccessor, Accessor targetReadAccessor) { Type nextType; Accessor toUse = targetWriteAccessor != null ? targetWriteAccessor : targetReadAccessor; - if ( Executables.isGetterMethod( toUse ) || + if ( accessorNaming.isGetterMethod( toUse ) || Executables.isFieldAccessor( toUse ) ) { nextType = typeFactory.getReturnType( (DeclaredType) typeBasedOnMethod( initial ).getTypeMirror(), diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java index 1715849b3..07e0e1a90 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java @@ -31,6 +31,7 @@ import javax.tools.Diagnostic.Kind; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.processor.ModelElementProcessor.ProcessorContext; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.RoundContext; @@ -50,12 +51,14 @@ public class DefaultModelElementProcessorContext implements ProcessorContext { private final TypeFactory typeFactory; private final VersionInformation versionInformation; private final Types delegatingTypes; + private final AccessorNamingUtils accessorNaming; public DefaultModelElementProcessorContext(ProcessingEnvironment processingEnvironment, Options options, RoundContext roundContext) { this.processingEnvironment = processingEnvironment; this.messager = new DelegatingMessager( processingEnvironment.getMessager() ); + this.accessorNaming = roundContext.getAnnotationProcessorContext().getAccessorNaming(); this.versionInformation = DefaultVersionInformation.fromProcessingEnvironment( processingEnvironment ); this.delegatingTypes = new TypesDecorator( processingEnvironment, versionInformation ); this.typeFactory = new TypeFactory( @@ -91,6 +94,11 @@ public class DefaultModelElementProcessorContext implements ProcessorContext { return messager; } + @Override + public AccessorNamingUtils getAccessorNaming() { + return accessorNaming; + } + @Override public Options getOptions() { return options; 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 caed18144..d5900a422 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 @@ -62,6 +62,7 @@ import org.mapstruct.ap.internal.prism.MapperPrism; import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism; import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; import org.mapstruct.ap.internal.processor.creation.MappingResolverImpl; +import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.MapperConfiguration; import org.mapstruct.ap.internal.util.Message; @@ -85,6 +86,7 @@ public class MapperCreationProcessor implements ModelElementProcessor mapperReferences = initReferencedMappers( mapperTypeElement, mapperConfig ); @@ -104,6 +107,7 @@ public class MapperCreationProcessor implements ModelElementProcessor 1 ) { messager.printMessage( @@ -484,7 +504,9 @@ public class MapperCreationProcessor implements ModelElementProcessor 1 ) { messager.printMessage( @@ -497,7 +519,13 @@ public class MapperCreationProcessor implements ModelElementProcessor process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) { this.messager = context.getMessager(); this.typeFactory = context.getTypeFactory(); + this.accessorNaming = context.getAccessorNaming(); this.typeUtils = context.getTypeUtils(); this.elementUtils = context.getElementUtils(); @@ -265,6 +268,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor { FormattingMessager getMessager(); + AccessorNamingUtils getAccessorNaming(); + Options getOptions(); VersionInformation getVersionInformation(); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/AccessorNamingUtils.java b/processor/src/main/java/org/mapstruct/ap/internal/util/AccessorNamingUtils.java new file mode 100644 index 000000000..536498d71 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/AccessorNamingUtils.java @@ -0,0 +1,132 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.internal.util; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleElementVisitor6; +import javax.lang.model.util.SimpleTypeVisitor6; + +import org.mapstruct.ap.internal.util.accessor.Accessor; +import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor; +import org.mapstruct.ap.spi.AccessorNamingStrategy; +import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy; +import org.mapstruct.ap.spi.MethodType; + +import static org.mapstruct.ap.internal.util.Executables.isPublic; + +/** + * Utils for working with the {@link AccessorNamingStrategy}. + * + * @author Filip Hrisafov + */ +public final class AccessorNamingUtils { + + private final AccessorNamingStrategy accessorNamingStrategy; + + public AccessorNamingUtils() { + accessorNamingStrategy = Services.get( + AccessorNamingStrategy.class, new DefaultAccessorNamingStrategy() + ); + } + + public boolean isGetterMethod(Accessor method) { + ExecutableElement executable = method.getExecutable(); + return executable != null && isPublic( method ) && + executable.getParameters().isEmpty() && + accessorNamingStrategy.getMethodType( executable ) == MethodType.GETTER; + } + + public boolean isPresenceCheckMethod(Accessor method) { + if ( !( method instanceof ExecutableElementAccessor ) ) { + return false; + } + ExecutableElement executable = method.getExecutable(); + return executable != null + && isPublic( method ) + && executable.getParameters().isEmpty() + && ( executable.getReturnType().getKind() == TypeKind.BOOLEAN || + "java.lang.Boolean".equals( getQualifiedName( executable.getReturnType() ) ) ) + && accessorNamingStrategy.getMethodType( executable ) == MethodType.PRESENCE_CHECKER; + } + + public boolean isSetterMethod(Accessor method) { + ExecutableElement executable = method.getExecutable(); + return executable != null + && isPublic( method ) + && executable.getParameters().size() == 1 + && accessorNamingStrategy.getMethodType( executable ) == MethodType.SETTER; + } + + public boolean isAdderMethod(Accessor method) { + ExecutableElement executable = method.getExecutable(); + return executable != null + && isPublic( method ) + && executable.getParameters().size() == 1 + && accessorNamingStrategy.getMethodType( executable ) == MethodType.ADDER; + } + + public String getPropertyName(Accessor accessor) { + ExecutableElement executable = accessor.getExecutable(); + return executable != null ? accessorNamingStrategy.getPropertyName( executable ) : + accessor.getSimpleName().toString(); + } + + /** + * @param adderMethod the adder method + * + * @return the 'element name' to which an adder method applies. If. e.g. an adder method is named + * {@code addChild(Child v)}, the element name would be 'Child'. + */ + public String getElementNameForAdder(Accessor adderMethod) { + ExecutableElement executable = adderMethod.getExecutable(); + return executable != null ? accessorNamingStrategy.getElementName( executable ) : null; + } + + private static String getQualifiedName(TypeMirror type) { + DeclaredType declaredType = type.accept( + new SimpleTypeVisitor6() { + @Override + public DeclaredType visitDeclared(DeclaredType t, Void p) { + return t; + } + }, + null + ); + + if ( declaredType == null ) { + return null; + } + + TypeElement typeElement = declaredType.asElement().accept( + new SimpleElementVisitor6() { + @Override + public TypeElement visitType(TypeElement e, Void p) { + return e; + } + }, + null + ); + + return typeElement != null ? typeElement.getQualifiedName().toString() : null; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java b/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java index 2474c1558..22044e979 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java @@ -33,10 +33,12 @@ import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor; public class AnnotationProcessorContext { private List astModifyingAnnotationProcessors; + private AccessorNamingUtils accessorNaming; public AnnotationProcessorContext() { astModifyingAnnotationProcessors = java.util.Collections.unmodifiableList( findAstModifyingAnnotationProcessors() ); + this.accessorNaming = new AccessorNamingUtils(); } private static List findAstModifyingAnnotationProcessors() { @@ -56,4 +58,8 @@ public class AnnotationProcessorContext { public List getAstModifyingAnnotationProcessors() { return astModifyingAnnotationProcessors; } + + public AccessorNamingUtils getAccessorNaming() { + return accessorNaming; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java index f70b5fcff..e4e14c39b 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java @@ -36,17 +36,12 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; -import javax.lang.model.util.SimpleElementVisitor6; -import javax.lang.model.util.SimpleTypeVisitor6; import org.mapstruct.ap.internal.prism.AfterMappingPrism; import org.mapstruct.ap.internal.prism.BeforeMappingPrism; import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor; import org.mapstruct.ap.internal.util.accessor.VariableElementAccessor; -import org.mapstruct.ap.spi.AccessorNamingStrategy; -import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy; -import org.mapstruct.ap.spi.MethodType; import org.mapstruct.ap.spi.TypeHierarchyErroneousException; /** @@ -69,20 +64,9 @@ public class Executables { DEFAULT_METHOD = method; } - private static final AccessorNamingStrategy ACCESSOR_NAMING_STRATEGY = Services.get( - AccessorNamingStrategy.class, new DefaultAccessorNamingStrategy() - ); - private Executables() { } - public static boolean isGetterMethod(Accessor method) { - ExecutableElement executable = method.getExecutable(); - return executable != null && isPublic( method ) && - executable.getParameters().isEmpty() && - ACCESSOR_NAMING_STRATEGY.getMethodType( executable ) == MethodType.GETTER; - } - /** * An {@link Accessor} is a field accessor, if it doesn't have an executable element, is public and it is not * static. @@ -96,36 +80,7 @@ public class Executables { return executable == null && isPublic( accessor ) && isNotStatic( accessor ); } - public static boolean isPresenceCheckMethod(Accessor method) { - if ( !( method instanceof ExecutableElementAccessor ) ) { - return false; - } - ExecutableElement executable = method.getExecutable(); - return executable != null - && isPublic( method ) - && executable.getParameters().isEmpty() - && ( executable.getReturnType().getKind() == TypeKind.BOOLEAN || - "java.lang.Boolean".equals( getQualifiedName( executable.getReturnType() ) ) ) - && ACCESSOR_NAMING_STRATEGY.getMethodType( executable ) == MethodType.PRESENCE_CHECKER; - } - - public static boolean isSetterMethod(Accessor method) { - ExecutableElement executable = method.getExecutable(); - return executable != null - && isPublic( method ) - && executable.getParameters().size() == 1 - && ACCESSOR_NAMING_STRATEGY.getMethodType( executable ) == MethodType.SETTER; - } - - public static boolean isAdderMethod(Accessor method) { - ExecutableElement executable = method.getExecutable(); - return executable != null - && isPublic( method ) - && executable.getParameters().size() == 1 - && ACCESSOR_NAMING_STRATEGY.getMethodType( executable ) == MethodType.ADDER; - } - - private static boolean isPublic(Accessor method) { + static boolean isPublic(Accessor method) { return method.getModifiers().contains( Modifier.PUBLIC ); } @@ -137,12 +92,6 @@ public class Executables { return accessor != null && accessor.getModifiers().contains( Modifier.FINAL ); } - public static String getPropertyName(Accessor accessor) { - ExecutableElement executable = accessor.getExecutable(); - return executable != null ? ACCESSOR_NAMING_STRATEGY.getPropertyName( executable ) : - accessor.getSimpleName().toString(); - } - public static boolean isDefaultMethod(ExecutableElement method) { try { return DEFAULT_METHOD != null && Boolean.TRUE.equals( DEFAULT_METHOD.invoke( method ) ); @@ -155,16 +104,6 @@ public class Executables { } } - /** - * @param adderMethod the adder method - * @return the 'element name' to which an adder method applies. If. e.g. an adder method is named - * {@code addChild(Child v)}, the element name would be 'Child'. - */ - public static String getElementNameForAdder(Accessor adderMethod) { - ExecutableElement executable = adderMethod.getExecutable(); - return executable != null ? ACCESSOR_NAMING_STRATEGY.getElementName( executable ) : null; - } - /** * @param mirror the type mirror * @@ -356,33 +295,4 @@ public class Executables { public static boolean isBeforeMappingMethod(ExecutableElement executableElement) { return BeforeMappingPrism.getInstanceOn( executableElement ) != null; } - - private static String getQualifiedName(TypeMirror type) { - DeclaredType declaredType = type.accept( - new SimpleTypeVisitor6() { - @Override - public DeclaredType visitDeclared(DeclaredType t, Void p) { - return t; - } - }, - null - ); - - if ( declaredType == null ) { - return null; - } - - TypeElement typeElement = declaredType.asElement().accept( - new SimpleElementVisitor6() { - @Override - public TypeElement visitType(TypeElement e, Void p) { - return e; - } - }, - null - ); - - return typeElement != null ? typeElement.getQualifiedName().toString() : null; - } - } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java index d26342244..b50711edf 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java @@ -36,11 +36,11 @@ public class Filters { private Filters() { } - public static List getterMethodsIn(List elements) { + public static List getterMethodsIn(AccessorNamingUtils accessorNaming, List elements) { List getterMethods = new LinkedList(); for ( Accessor method : elements ) { - if ( Executables.isGetterMethod( method ) ) { + if ( accessorNaming.isGetterMethod( method ) ) { getterMethods.add( method ); } } @@ -60,11 +60,12 @@ public class Filters { return fieldAccessors; } - public static List presenceCheckMethodsIn(List elements) { + public static List presenceCheckMethodsIn(AccessorNamingUtils accessorNaming, + List elements) { List presenceCheckMethods = new LinkedList(); for ( Accessor method : elements ) { - if ( Executables.isPresenceCheckMethod( method ) ) { + if ( accessorNaming.isPresenceCheckMethod( method ) ) { presenceCheckMethods.add( (ExecutableElementAccessor) method ); } } @@ -72,22 +73,22 @@ public class Filters { return presenceCheckMethods; } - public static List setterMethodsIn(List elements) { + public static List setterMethodsIn(AccessorNamingUtils accessorNaming, List elements) { List setterMethods = new LinkedList(); for ( Accessor method : elements ) { - if ( Executables.isSetterMethod( method ) ) { + if ( accessorNaming.isSetterMethod( method ) ) { setterMethods.add( method ); } } return setterMethods; } - public static List adderMethodsIn(List elements) { + public static List adderMethodsIn(AccessorNamingUtils accessorNaming, List elements) { List adderMethods = new LinkedList(); for ( Accessor method : elements ) { - if ( Executables.isAdderMethod( method ) ) { + if ( accessorNaming.isAdderMethod( method ) ) { adderMethods.add( method ); } } diff --git a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DateFormatValidatorFactoryTest.java b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DateFormatValidatorFactoryTest.java index 7afafc0d6..7b9330ab4 100755 --- a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DateFormatValidatorFactoryTest.java +++ b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DateFormatValidatorFactoryTest.java @@ -168,6 +168,7 @@ public class DateFormatValidatorFactoryTest { null, null, null, + null, voidTypeMirror, null, null, diff --git a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java index 73796af0f..da16066e3 100755 --- a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java +++ b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java @@ -119,6 +119,7 @@ public class DefaultConversionContextTest { null, null, null, + null, voidTypeMirror, null, null,