mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#196 moving getGetters, getSetters and getAlternativeTargetAccessors to Type, initializing them lazy.
This commit is contained in:
parent
8d6c216a2f
commit
529acf6055
@ -19,6 +19,7 @@
|
|||||||
package org.mapstruct.ap.model.common;
|
package org.mapstruct.ap.model.common;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -26,11 +27,16 @@ import java.util.Set;
|
|||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.Name;
|
import javax.lang.model.element.Name;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
|
import org.mapstruct.ap.util.Executables;
|
||||||
|
import org.mapstruct.ap.util.Filters;
|
||||||
|
import org.mapstruct.ap.util.TypeUtilsJDK6Fix;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents (a reference to) the type of a bean property, parameter etc. Types are managed per generated source file.
|
* Represents (a reference to) the type of a bean property, parameter etc. Types are managed per generated source file.
|
||||||
@ -45,6 +51,7 @@ import javax.lang.model.util.Types;
|
|||||||
public class Type extends ModelElement implements Comparable<Type> {
|
public class Type extends ModelElement implements Comparable<Type> {
|
||||||
|
|
||||||
private final Types typeUtils;
|
private final Types typeUtils;
|
||||||
|
private final Elements elementUtils;
|
||||||
|
|
||||||
private final TypeMirror typeMirror;
|
private final TypeMirror typeMirror;
|
||||||
private final TypeElement typeElement;
|
private final TypeElement typeElement;
|
||||||
@ -64,19 +71,31 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
private final boolean isImported;
|
private final boolean isImported;
|
||||||
private final List<String> enumConstants;
|
private final List<String> enumConstants;
|
||||||
|
|
||||||
|
private List<ExecutableElement> getters = null;
|
||||||
|
private List<ExecutableElement> setters = null;
|
||||||
|
private List<ExecutableElement> alternativeTargetAccessors = null;
|
||||||
|
|
||||||
//CHECKSTYLE:OFF
|
//CHECKSTYLE:OFF
|
||||||
public Type(Types typeUtils, TypeMirror typeMirror, TypeElement typeElement, List<Type> typeParameters,
|
public Type(Types typeUtils, Elements elementUtils,
|
||||||
Type implementationType, String packageName, String name, String qualifiedName, boolean isInterface,
|
TypeMirror typeMirror, TypeElement typeElement, List<Type> typeParameters,
|
||||||
boolean isEnumType, boolean isIterableType, boolean isCollectionType, boolean isMapType,
|
Type implementationType,
|
||||||
boolean isImported) {
|
String packageName, String name, String qualifiedName,
|
||||||
|
boolean isInterface,
|
||||||
|
boolean isEnumType, boolean isIterableType, boolean isCollectionType, boolean isMapType,
|
||||||
|
boolean isImported) {
|
||||||
|
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
|
this.elementUtils = elementUtils;
|
||||||
|
|
||||||
this.typeMirror = typeMirror;
|
this.typeMirror = typeMirror;
|
||||||
this.typeElement = typeElement;
|
this.typeElement = typeElement;
|
||||||
this.typeParameters = typeParameters;
|
this.typeParameters = typeParameters;
|
||||||
this.implementationType = implementationType;
|
this.implementationType = implementationType;
|
||||||
|
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.qualifiedName = qualifiedName;
|
this.qualifiedName = qualifiedName;
|
||||||
|
|
||||||
this.isInterface = isInterface;
|
this.isInterface = isInterface;
|
||||||
this.isEnumType = isEnumType;
|
this.isEnumType = isEnumType;
|
||||||
this.isIterableType = isIterableType;
|
this.isIterableType = isIterableType;
|
||||||
@ -206,6 +225,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
public Type erasure() {
|
public Type erasure() {
|
||||||
return new Type(
|
return new Type(
|
||||||
typeUtils,
|
typeUtils,
|
||||||
|
elementUtils,
|
||||||
typeUtils.erasure( typeMirror ),
|
typeUtils.erasure( typeMirror ),
|
||||||
typeElement,
|
typeElement,
|
||||||
typeParameters,
|
typeParameters,
|
||||||
@ -239,6 +259,79 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
return typeUtils.isAssignable( typeMirror, other.typeMirror );
|
return typeUtils.isAssignable( typeMirror, other.typeMirror );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getGetters
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of all getters (including 'is' for booleans).
|
||||||
|
*/
|
||||||
|
public List<ExecutableElement> getGetters() {
|
||||||
|
if (getters == null) {
|
||||||
|
List<? extends Element> members = elementUtils.getAllMembers( typeElement );
|
||||||
|
getters = Collections.unmodifiableList( Filters.getterMethodsIn( members ) );
|
||||||
|
}
|
||||||
|
return getters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getSetters
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of all setters
|
||||||
|
*/
|
||||||
|
public List<ExecutableElement> getSetters() {
|
||||||
|
if (setters == null) {
|
||||||
|
List<? extends Element> members = elementUtils.getAllMembers( typeElement );
|
||||||
|
setters = Collections.unmodifiableList( Filters.setterMethodsIn( members ) );
|
||||||
|
}
|
||||||
|
return setters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative accessors could be a getter for a collection. By means of the
|
||||||
|
* {@link java.util.Collection#addAll(java.util.Collection) } this getter can still
|
||||||
|
* be used as targetAccessor. JAXB XJC tool generates such constructs.
|
||||||
|
*
|
||||||
|
* This method can be extended when new cases come along.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of alternative target accessors.
|
||||||
|
*/
|
||||||
|
public List<ExecutableElement> getAlternativeTargetAccessors() {
|
||||||
|
if ( alternativeTargetAccessors == null ) {
|
||||||
|
|
||||||
|
List<ExecutableElement> result = new ArrayList<ExecutableElement>();
|
||||||
|
List<ExecutableElement> setterMethods = getSetters();
|
||||||
|
List<ExecutableElement> getterMethods = getGetters();
|
||||||
|
|
||||||
|
if ( getterMethods.size() > setterMethods.size() ) {
|
||||||
|
// there could be a getter method for a list that is not present as setter.
|
||||||
|
// a getter could substitute the setter in that case and act as setter.
|
||||||
|
// (assuming it is initialized)
|
||||||
|
for ( ExecutableElement getterMethod : getterMethods ) {
|
||||||
|
boolean matchFound = false;
|
||||||
|
String getterPropertyName = Executables.getPropertyName( getterMethod );
|
||||||
|
for ( ExecutableElement setterMethod : setterMethods ) {
|
||||||
|
String setterPropertyName = Executables.getPropertyName( setterMethod );
|
||||||
|
if ( getterPropertyName.equals( setterPropertyName ) ) {
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !matchFound && isCollection( getterMethod.getReturnType() ) ) {
|
||||||
|
result.add( getterMethod );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alternativeTargetAccessors = Collections.unmodifiableList( result );
|
||||||
|
}
|
||||||
|
return alternativeTargetAccessors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCollection( TypeMirror candidate ) {
|
||||||
|
String collectionName = Collection.class.getCanonicalName();
|
||||||
|
TypeMirror collectionType = typeUtils.erasure( elementUtils.getTypeElement( collectionName ).asType() );
|
||||||
|
return TypeUtilsJDK6Fix.isSubType( typeUtils, candidate, collectionType );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the length of the shortest path in the type hierarchy between this type and the specified other type.
|
* Returns the length of the shortest path in the type hierarchy between this type and the specified other type.
|
||||||
* Returns {@code -1} if this type is not assignable to the other type. Returns {@code 0} if this type is equal to
|
* Returns {@code -1} if this type is not assignable to the other type. Returns {@code 0} if this type is equal to
|
||||||
|
@ -162,7 +162,7 @@ public class TypeFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Type(
|
return new Type(
|
||||||
typeUtils,
|
typeUtils, elementUtils,
|
||||||
mirror,
|
mirror,
|
||||||
typeElement,
|
typeElement,
|
||||||
getTypeParameters( mirror ),
|
getTypeParameters( mirror ),
|
||||||
@ -283,6 +283,7 @@ public class TypeFactory {
|
|||||||
if ( implementationType != null ) {
|
if ( implementationType != null ) {
|
||||||
return new Type(
|
return new Type(
|
||||||
typeUtils,
|
typeUtils,
|
||||||
|
elementUtils,
|
||||||
typeUtils.getDeclaredType(
|
typeUtils.getDeclaredType(
|
||||||
implementationType.getTypeElement(),
|
implementationType.getTypeElement(),
|
||||||
declaredType.getTypeArguments().toArray( new TypeMirror[] { } )
|
declaredType.getTypeArguments().toArray( new TypeMirror[] { } )
|
||||||
|
@ -27,7 +27,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.Messager;
|
import javax.annotation.processing.Messager;
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
@ -70,7 +69,6 @@ import org.mapstruct.ap.option.ReportingPolicy;
|
|||||||
import org.mapstruct.ap.prism.DecoratedWithPrism;
|
import org.mapstruct.ap.prism.DecoratedWithPrism;
|
||||||
import org.mapstruct.ap.prism.MapperPrism;
|
import org.mapstruct.ap.prism.MapperPrism;
|
||||||
import org.mapstruct.ap.util.Executables;
|
import org.mapstruct.ap.util.Executables;
|
||||||
import org.mapstruct.ap.util.Filters;
|
|
||||||
import org.mapstruct.ap.util.MapperConfig;
|
import org.mapstruct.ap.util.MapperConfig;
|
||||||
import org.mapstruct.ap.util.Strings;
|
import org.mapstruct.ap.util.Strings;
|
||||||
|
|
||||||
@ -403,10 +401,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
Mapping mapping = method.getMappingByTargetPropertyName( targetPropertyName );
|
Mapping mapping = method.getMappingByTargetPropertyName( targetPropertyName );
|
||||||
String dateFormat = mapping != null ? mapping.getDateFormat() : null;
|
String dateFormat = mapping != null ? mapping.getDateFormat() : null;
|
||||||
String sourcePropertyName = mapping != null ? mapping.getSourcePropertyName() : targetPropertyName;
|
String sourcePropertyName = mapping != null ? mapping.getSourcePropertyName() : targetPropertyName;
|
||||||
TypeElement parameterElement = parameter.getType().getTypeElement();
|
List<ExecutableElement> sourceGetters = parameter.getType().getGetters();
|
||||||
List<ExecutableElement> sourceGetters = Filters.getterMethodsIn(
|
|
||||||
elementUtils.getAllMembers( parameterElement )
|
|
||||||
);
|
|
||||||
|
|
||||||
for ( ExecutableElement sourceAccessor : sourceGetters ) {
|
for ( ExecutableElement sourceAccessor : sourceGetters ) {
|
||||||
|
|
||||||
@ -454,15 +449,10 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeElement resultTypeElement = method.getResultType().getTypeElement();
|
// collect all target accessors
|
||||||
List<ExecutableElement> targetAccessors = Filters.setterMethodsIn(
|
List<ExecutableElement> targetAccessors = new ArrayList<ExecutableElement>();
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
targetAccessors.addAll( method.getResultType().getSetters() );
|
||||||
);
|
targetAccessors.addAll( method.getResultType().getAlternativeTargetAccessors() );
|
||||||
targetAccessors.addAll(
|
|
||||||
alternativeTargetAccessorMethodsIn(
|
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
for ( ExecutableElement targetAccessor : targetAccessors ) {
|
for ( ExecutableElement targetAccessor : targetAccessors ) {
|
||||||
String targetPropertyName = Executables.getPropertyName( targetAccessor );
|
String targetPropertyName = Executables.getPropertyName( targetAccessor );
|
||||||
@ -557,11 +547,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasSourceProperty(Parameter parameter, String propertyName) {
|
private boolean hasSourceProperty(Parameter parameter, String propertyName) {
|
||||||
TypeElement parameterTypeElement = parameter.getType().getTypeElement();
|
List<ExecutableElement> getters = parameter.getType().getGetters();
|
||||||
List<ExecutableElement> getters = Filters.getterMethodsIn(
|
|
||||||
elementUtils.getAllMembers( parameterTypeElement )
|
|
||||||
);
|
|
||||||
|
|
||||||
return Executables.getPropertyNames( getters ).contains( propertyName );
|
return Executables.getPropertyNames( getters ).contains( propertyName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,15 +557,11 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeElement resultTypeElement = method.getResultType().getTypeElement();
|
// collect all target accessors
|
||||||
List<ExecutableElement> targetAccessors = Filters.setterMethodsIn(
|
List<ExecutableElement> targetAccessors = new ArrayList<ExecutableElement>();
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
targetAccessors.addAll( method.getResultType().getSetters() );
|
||||||
);
|
targetAccessors.addAll( method.getResultType().getAlternativeTargetAccessors() );
|
||||||
targetAccessors.addAll(
|
|
||||||
alternativeTargetAccessorMethodsIn(
|
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
Set<String> targetProperties = Executables.getPropertyNames( targetAccessors );
|
Set<String> targetProperties = Executables.getPropertyNames( targetAccessors );
|
||||||
|
|
||||||
boolean foundUnmappedProperty = false;
|
boolean foundUnmappedProperty = false;
|
||||||
@ -1361,42 +1343,4 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
return typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
|
return typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
|
||||||
typeUtils.isAssignable( sourceValueType, targetValueType );
|
typeUtils.isAssignable( sourceValueType, targetValueType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A getter could be an alternative getReturnType-accessor if a setter is not available, and the
|
|
||||||
* getReturnType is a collection.
|
|
||||||
*
|
|
||||||
* Provided such a getter is initialized lazy by the getReturnType class, e.g. in generated JAXB beans.
|
|
||||||
*
|
|
||||||
* @param elements
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private List<ExecutableElement> alternativeTargetAccessorMethodsIn(Iterable<? extends Element> elements) {
|
|
||||||
List<ExecutableElement> setterMethods = Filters.setterMethodsIn( elements );
|
|
||||||
List<ExecutableElement> getterMethods = Filters.getterMethodsIn( elements );
|
|
||||||
List<ExecutableElement> alternativeTargetAccessorsMethods = new LinkedList<ExecutableElement>();
|
|
||||||
|
|
||||||
if ( getterMethods.size() > setterMethods.size() ) {
|
|
||||||
// there could be a getter method for a list that is not present as setter.
|
|
||||||
// a getter could substitute the setter in that case and act as setter.
|
|
||||||
// (assuming it is initialized)
|
|
||||||
for ( ExecutableElement getterMethod : getterMethods ) {
|
|
||||||
boolean matchFound = false;
|
|
||||||
String getterPropertyName = Executables.getPropertyName( getterMethod );
|
|
||||||
for ( ExecutableElement setterMethod : setterMethods ) {
|
|
||||||
String setterPropertyName = Executables.getPropertyName( setterMethod );
|
|
||||||
if ( getterPropertyName.equals( setterPropertyName ) ) {
|
|
||||||
matchFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( !matchFound && typeFactory.getReturnType( getterMethod ).isCollectionType() ) {
|
|
||||||
alternativeTargetAccessorsMethods.add( getterMethod );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return alternativeTargetAccessorsMethods;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user