mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#782 Add BuilderInfo to SPI
The implementors of the SPI should return all the required information
This commit is contained in:
parent
d99a4cc217
commit
45abe9e35b
@ -52,7 +52,7 @@ import org.mapstruct.ap.internal.processor.ModelElementProcessor.ProcessorContex
|
|||||||
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
||||||
import org.mapstruct.ap.internal.util.AnnotationProcessorContext;
|
import org.mapstruct.ap.internal.util.AnnotationProcessorContext;
|
||||||
import org.mapstruct.ap.internal.util.RoundContext;
|
import org.mapstruct.ap.internal.util.RoundContext;
|
||||||
import org.mapstruct.ap.internal.util.TypeHierarchyErroneousException;
|
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JSR 269 annotation {@link Processor} which generates the implementations for mapper interfaces (interfaces
|
* A JSR 269 annotation {@link Processor} which generates the implementations for mapper interfaces (interfaces
|
||||||
|
@ -40,8 +40,8 @@ import javax.tools.Diagnostic;
|
|||||||
import org.mapstruct.ap.internal.model.PropertyMapping.ConstantMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.ConstantMappingBuilder;
|
||||||
import org.mapstruct.ap.internal.model.PropertyMapping.JavaExpressionMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.JavaExpressionMappingBuilder;
|
||||||
import org.mapstruct.ap.internal.model.PropertyMapping.PropertyMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.PropertyMappingBuilder;
|
||||||
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||||
import org.mapstruct.ap.internal.model.common.ParameterBinding;
|
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer;
|
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer;
|
||||||
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer.GraphAnalyzerBuilder;
|
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer.GraphAnalyzerBuilder;
|
||||||
@ -244,33 +244,8 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
( (ForgedMethod) method ).addThrownTypes( factoryMethod.getThrownTypes() );
|
( (ForgedMethod) method ).addThrownTypes( factoryMethod.getThrownTypes() );
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodReference finalizeMethod = null;
|
MethodReference finalizeMethod = getFinalizeMethod(
|
||||||
if (
|
resultType == null ? method.getReturnType() : resultType );
|
||||||
!method.getReturnType().isVoid() &&
|
|
||||||
( resultType != null
|
|
||||||
&& !ctx.getTypeUtils().isAssignable(
|
|
||||||
resultType.getMappingType().getTypeMirror(),
|
|
||||||
resultType.getTypeMirror()
|
|
||||||
) ||
|
|
||||||
!ctx.getTypeUtils().isSameType(
|
|
||||||
method.getReturnType().getMappingType().getTypeMirror(),
|
|
||||||
method.getReturnType().getTypeMirror()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
finalizeMethod = MethodReference.forForgedMethod(
|
|
||||||
new ForgedMethod(
|
|
||||||
"build",
|
|
||||||
method.getReturnType(),
|
|
||||||
method.getReturnType(),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
Collections.<Parameter>emptyList(),
|
|
||||||
null
|
|
||||||
),
|
|
||||||
Collections.<ParameterBinding>emptyList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BeanMappingMethod(
|
return new BeanMappingMethod(
|
||||||
method,
|
method,
|
||||||
@ -285,6 +260,20 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MethodReference getFinalizeMethod(Type resultType) {
|
||||||
|
if ( method.getReturnType().isVoid() ||
|
||||||
|
resultType.getMappingType().isAssignableTo( resultType ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BuilderType builderType = resultType.getBuilderType();
|
||||||
|
if ( builderType == null ) {
|
||||||
|
// If the mapping type is assignable to the result type this should never happen
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MethodReference.forMethodCall( builderType.getBuildMethod() );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there were nested defined targets that have not been handled. Then we need to process them at the end.
|
* If there were nested defined targets that have not been handled. Then we need to process them at the end.
|
||||||
*/
|
*/
|
||||||
|
@ -118,7 +118,7 @@ public class MethodReference extends ModelElement implements Assignment {
|
|||||||
this.name = method.getName();
|
this.name = method.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodReference(String name, Type definingType) {
|
private MethodReference(String name, Type definingType, boolean isStatic) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.definingType = definingType;
|
this.definingType = definingType;
|
||||||
this.sourceParameters = Collections.emptyList();
|
this.sourceParameters = Collections.emptyList();
|
||||||
@ -130,7 +130,7 @@ public class MethodReference extends ModelElement implements Assignment {
|
|||||||
this.contextParam = null;
|
this.contextParam = null;
|
||||||
this.parameterBindings = Collections.emptyList();
|
this.parameterBindings = Collections.emptyList();
|
||||||
this.providingParameter = null;
|
this.providingParameter = null;
|
||||||
this.isStatic = true;
|
this.isStatic = isStatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapperReference getDeclaringMapper() {
|
public MapperReference getDeclaringMapper() {
|
||||||
@ -335,6 +335,10 @@ public class MethodReference extends ModelElement implements Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MethodReference forStaticBuilder(String builderCreationMethod, Type definingType) {
|
public static MethodReference forStaticBuilder(String builderCreationMethod, Type definingType) {
|
||||||
return new MethodReference( builderCreationMethod, definingType );
|
return new MethodReference( builderCreationMethod, definingType, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodReference forMethodCall(String methodName) {
|
||||||
|
return new MethodReference( methodName, null, false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* 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.model.common;
|
||||||
|
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.spi.BuilderInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class BuilderType {
|
||||||
|
|
||||||
|
private final Type builder;
|
||||||
|
private final Type owner;
|
||||||
|
private final Type buildingType;
|
||||||
|
private final ExecutableElement builderCreationMethod;
|
||||||
|
private final ExecutableElement buildMethod;
|
||||||
|
|
||||||
|
private BuilderType(
|
||||||
|
Type builder,
|
||||||
|
Type owner,
|
||||||
|
Type buildingType,
|
||||||
|
ExecutableElement builderCreationMethod,
|
||||||
|
ExecutableElement buildMethod
|
||||||
|
) {
|
||||||
|
this.builder = builder;
|
||||||
|
this.owner = owner;
|
||||||
|
this.buildingType = buildingType;
|
||||||
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
|
this.buildMethod = buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getBuilder() {
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getBuildingType() {
|
||||||
|
return buildingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutableElement getBuilderCreationMethod() {
|
||||||
|
return builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuildMethod() {
|
||||||
|
return buildMethod.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuilderInfo asBuilderInfo() {
|
||||||
|
return new BuilderInfo.Builder()
|
||||||
|
.builderCreationMethod( this.builderCreationMethod )
|
||||||
|
.buildMethod( this.buildMethod )
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BuilderType create(BuilderInfo builderInfo, Type typeToBuild, TypeFactory typeFactory,
|
||||||
|
Types typeUtils) {
|
||||||
|
if ( builderInfo == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ExecutableElement buildMethod = builderInfo.getBuildMethod();
|
||||||
|
if ( !typeUtils.isAssignable( buildMethod.getReturnType(), typeToBuild.getTypeMirror() ) ) {
|
||||||
|
//TODO throw error
|
||||||
|
throw new IllegalArgumentException( "Build return type is not assignable" );
|
||||||
|
}
|
||||||
|
|
||||||
|
Type builder = typeFactory.getType( builderInfo.getBuilderCreationMethod().getReturnType() );
|
||||||
|
ExecutableElement builderCreationMethod = builderInfo.getBuilderCreationMethod();
|
||||||
|
Type owner;
|
||||||
|
TypeMirror builderCreationOwner = builderCreationMethod.getEnclosingElement().asType();
|
||||||
|
if ( typeUtils.isSameType( builderCreationOwner, typeToBuild.getTypeMirror() ) ) {
|
||||||
|
owner = typeToBuild;
|
||||||
|
}
|
||||||
|
else if ( typeUtils.isSameType( builder.getTypeMirror(), builderCreationOwner ) ) {
|
||||||
|
owner = builder;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
owner = typeFactory.getType( builderCreationOwner );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new BuilderType(
|
||||||
|
builder,
|
||||||
|
owner,
|
||||||
|
typeToBuild,
|
||||||
|
builderCreationMethod,
|
||||||
|
buildMethod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,7 @@ import org.mapstruct.ap.internal.util.Filters;
|
|||||||
import org.mapstruct.ap.internal.util.Nouns;
|
import org.mapstruct.ap.internal.util.Nouns;
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor;
|
||||||
|
import org.mapstruct.ap.spi.BuilderInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@ -72,7 +73,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
|
|
||||||
private final ImplementationType implementationType;
|
private final ImplementationType implementationType;
|
||||||
private final Type componentType;
|
private final Type componentType;
|
||||||
private final Type builderType;
|
private final BuilderType builderType;
|
||||||
|
|
||||||
private final String packageName;
|
private final String packageName;
|
||||||
private final String name;
|
private final String name;
|
||||||
@ -105,7 +106,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
|
public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
|
||||||
TypeMirror typeMirror, TypeElement typeElement,
|
TypeMirror typeMirror, TypeElement typeElement,
|
||||||
List<Type> typeParameters, ImplementationType implementationType, Type componentType,
|
List<Type> typeParameters, ImplementationType implementationType, Type componentType,
|
||||||
Type builderType,
|
BuilderInfo builderInfo,
|
||||||
String packageName, String name, String qualifiedName,
|
String packageName, String name, String qualifiedName,
|
||||||
boolean isInterface, boolean isEnumType, boolean isIterableType,
|
boolean isInterface, boolean isEnumType, boolean isIterableType,
|
||||||
boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported) {
|
boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported) {
|
||||||
@ -119,7 +120,6 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
this.typeParameters = typeParameters;
|
this.typeParameters = typeParameters;
|
||||||
this.componentType = componentType;
|
this.componentType = componentType;
|
||||||
this.implementationType = implementationType;
|
this.implementationType = implementationType;
|
||||||
this.builderType = builderType;
|
|
||||||
|
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -149,6 +149,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
else {
|
else {
|
||||||
enumConstants = Collections.emptyList();
|
enumConstants = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.builderType = BuilderType.create( builderInfo, this, this.typeFactory, this.typeUtils );
|
||||||
}
|
}
|
||||||
//CHECKSTYLE:ON
|
//CHECKSTYLE:ON
|
||||||
|
|
||||||
@ -176,12 +178,12 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getBuilderType() {
|
public BuilderType getBuilderType() {
|
||||||
return builderType;
|
return builderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getMappingType() {
|
public Type getMappingType() {
|
||||||
return builderType != null ? builderType : this;
|
return builderType != null ? builderType.getBuilder() : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrimitive() {
|
public boolean isPrimitive() {
|
||||||
@ -366,7 +368,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
typeParameters,
|
typeParameters,
|
||||||
implementationType,
|
implementationType,
|
||||||
componentType,
|
componentType,
|
||||||
builderType,
|
builderType == null ? null : builderType.asBuilderInfo(),
|
||||||
packageName,
|
packageName,
|
||||||
name,
|
name,
|
||||||
qualifiedName,
|
qualifiedName,
|
||||||
|
@ -58,11 +58,12 @@ import org.mapstruct.ap.internal.util.Collections;
|
|||||||
import org.mapstruct.ap.internal.util.JavaStreamConstants;
|
import org.mapstruct.ap.internal.util.JavaStreamConstants;
|
||||||
import org.mapstruct.ap.internal.util.RoundContext;
|
import org.mapstruct.ap.internal.util.RoundContext;
|
||||||
import org.mapstruct.ap.internal.util.Services;
|
import org.mapstruct.ap.internal.util.Services;
|
||||||
import org.mapstruct.ap.internal.util.TypeHierarchyErroneousException;
|
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||||
|
import org.mapstruct.ap.spi.BuilderInfo;
|
||||||
import org.mapstruct.ap.spi.BuilderProvider;
|
import org.mapstruct.ap.spi.BuilderProvider;
|
||||||
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
||||||
|
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor;
|
import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor;
|
||||||
import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity;
|
import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity;
|
||||||
@ -170,7 +171,7 @@ public class TypeFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImplementationType implementationType = getImplementationType( mirror );
|
ImplementationType implementationType = getImplementationType( mirror );
|
||||||
Type builderType = findBuilder( mirror );
|
BuilderInfo builderInfo = findBuilder( mirror );
|
||||||
|
|
||||||
boolean isIterableType = typeUtils.isSubtype( mirror, iterableType );
|
boolean isIterableType = typeUtils.isSubtype( mirror, iterableType );
|
||||||
boolean isCollectionType = typeUtils.isSubtype( mirror, collectionType );
|
boolean isCollectionType = typeUtils.isSubtype( mirror, collectionType );
|
||||||
@ -256,7 +257,7 @@ public class TypeFactory {
|
|||||||
getTypeParameters( mirror, false ),
|
getTypeParameters( mirror, false ),
|
||||||
implementationType,
|
implementationType,
|
||||||
componentType,
|
componentType,
|
||||||
builderType,
|
builderInfo,
|
||||||
packageName,
|
packageName,
|
||||||
name,
|
name,
|
||||||
qualifiedName,
|
qualifiedName,
|
||||||
@ -486,9 +487,8 @@ public class TypeFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type findBuilder(TypeMirror type) {
|
private BuilderInfo findBuilder(TypeMirror type) {
|
||||||
TypeMirror builder = BUILDER_PROVIDER.findBuilder( type, elementUtils, typeUtils );
|
return BUILDER_PROVIDER.findBuilderInfo( type, elementUtils, typeUtils );
|
||||||
return builder == null ? null : getType( builder );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeMirror getComponentType(TypeMirror mirror) {
|
private TypeMirror getComponentType(TypeMirror mirror) {
|
||||||
|
@ -22,13 +22,12 @@ import static java.util.Collections.singletonList;
|
|||||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.Modifier;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.ExecutableType;
|
import javax.lang.model.type.ExecutableType;
|
||||||
@ -46,6 +45,7 @@ import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
|||||||
import org.mapstruct.ap.internal.model.MethodReference;
|
import org.mapstruct.ap.internal.model.MethodReference;
|
||||||
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
||||||
import org.mapstruct.ap.internal.model.common.Assignment;
|
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||||
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
||||||
@ -60,7 +60,6 @@ import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
|
|||||||
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
|
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
|
||||||
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
|
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
|
||||||
import org.mapstruct.ap.internal.util.Collections;
|
import org.mapstruct.ap.internal.util.Collections;
|
||||||
import org.mapstruct.ap.internal.util.Executables;
|
|
||||||
import org.mapstruct.ap.internal.util.FormattingMessager;
|
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||||
import org.mapstruct.ap.internal.util.Message;
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
@ -143,7 +142,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
||||||
|
|
||||||
if (matchingFactoryMethods.isEmpty()) {
|
if (matchingFactoryMethods.isEmpty()) {
|
||||||
return findBuilderFactoryMethod( mappingMethod, targetType );
|
return findBuilderFactoryMethod( targetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( matchingFactoryMethods.size() > 1 ) {
|
if ( matchingFactoryMethods.size() > 1 ) {
|
||||||
@ -166,39 +165,26 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
matchingFactoryMethod.getParameterBindings() );
|
matchingFactoryMethod.getParameterBindings() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodReference findBuilderFactoryMethod(Method mappingMethod, Type targetType) {
|
private MethodReference findBuilderFactoryMethod(Type targetType) {
|
||||||
if ( targetType.getBuilderType() == null ) {
|
BuilderType builder = targetType.getBuilderType();
|
||||||
return null;
|
if ( builder == null ) {
|
||||||
}
|
|
||||||
Type builderType = targetType.getBuilderType();
|
|
||||||
|
|
||||||
Type returnType = mappingMethod.getReturnType();
|
|
||||||
List<ExecutableElement> builderCreators = new ArrayList<ExecutableElement>();
|
|
||||||
for ( ExecutableElement executableElement : Executables.getAllEnclosedExecutableElements(
|
|
||||||
elementsUtils,
|
|
||||||
returnType.getTypeElement()
|
|
||||||
) ) {
|
|
||||||
if ( !executableElement.getModifiers().containsAll( Arrays.asList( Modifier.PUBLIC, Modifier.STATIC ) )
|
|
||||||
|| !executableElement.getParameters().isEmpty()
|
|
||||||
|| !typeUtils.isSameType( executableElement.getReturnType(), builderType.getTypeMirror() )) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
builderCreators.add( executableElement );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( builderCreators.size() == 1 ) {
|
|
||||||
return MethodReference.forStaticBuilder( first( builderCreators ).getSimpleName().toString(), targetType );
|
|
||||||
}
|
|
||||||
else if ( builderCreators.size() > 1 ) {
|
|
||||||
//error
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the default constructor, if it exists, and construct the FactoryMethod
|
ExecutableElement builderCreationMethod = builder.getBuilderCreationMethod();
|
||||||
// We could also live with assuming it exists
|
if ( builderCreationMethod.getKind() == ElementKind.CONSTRUCTOR ) {
|
||||||
|
// If the builder creation method is a constructor it would be handled properly down the line
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !builder.getBuildingType().isAssignableTo( targetType ) ) {
|
||||||
|
//TODO print error message
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MethodReference.forStaticBuilder( builderCreationMethod.getSimpleName().toString(), builder.getOwner() );
|
||||||
|
}
|
||||||
|
|
||||||
private MapperReference findMapperReference(Method method) {
|
private MapperReference findMapperReference(Method method) {
|
||||||
for ( MapperReference ref : mapperReferences ) {
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
|
@ -47,6 +47,7 @@ import org.mapstruct.ap.internal.util.accessor.VariableElementAccessor;
|
|||||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy;
|
import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.spi.MethodType;
|
import org.mapstruct.ap.spi.MethodType;
|
||||||
|
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides functionality around {@link ExecutableElement}s.
|
* Provides functionality around {@link ExecutableElement}s.
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* 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.spi;
|
||||||
|
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class BuilderInfo {
|
||||||
|
|
||||||
|
private final ExecutableElement builderCreationMethod;
|
||||||
|
private final ExecutableElement buildMethod;
|
||||||
|
|
||||||
|
private BuilderInfo(ExecutableElement builderCreationMethod, ExecutableElement buildMethod) {
|
||||||
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
|
this.buildMethod = buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutableElement getBuilderCreationMethod() {
|
||||||
|
return builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutableElement getBuildMethod() {
|
||||||
|
return buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private ExecutableElement builderCreationMethod;
|
||||||
|
private ExecutableElement buildMethod;
|
||||||
|
|
||||||
|
public Builder builderCreationMethod(ExecutableElement method) {
|
||||||
|
this.builderCreationMethod = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder buildMethod(ExecutableElement method) {
|
||||||
|
this.buildMethod = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuilderInfo build() {
|
||||||
|
if ( builderCreationMethod == null ) {
|
||||||
|
throw new IllegalArgumentException( "Builder creation method is mandatory" );
|
||||||
|
}
|
||||||
|
else if ( buildMethod == null ) {
|
||||||
|
throw new IllegalArgumentException( "Build method is mandatory" );
|
||||||
|
}
|
||||||
|
return new BuilderInfo( builderCreationMethod, buildMethod );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,5 +29,5 @@ import javax.lang.model.util.Types;
|
|||||||
*/
|
*/
|
||||||
public interface BuilderProvider {
|
public interface BuilderProvider {
|
||||||
|
|
||||||
TypeMirror findBuilder(TypeMirror type, Elements elements, Types types);
|
BuilderInfo findBuilderInfo(TypeMirror type, Elements elements, Types types);
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ import java.util.List;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
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.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.ElementFilter;
|
import javax.lang.model.util.ElementFilter;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
@ -42,7 +42,19 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror findBuilder(TypeMirror type, Elements elements, Types types) {
|
public BuilderInfo findBuilderInfo(TypeMirror type, Elements elements, Types types) {
|
||||||
|
TypeElement typeElement = getTypeElement( type );
|
||||||
|
if ( typeElement == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findBuilderInfo( typeElement, elements, types );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TypeElement getTypeElement(TypeMirror type) {
|
||||||
|
if ( type.getKind() == TypeKind.ERROR ) {
|
||||||
|
throw new TypeHierarchyErroneousException( type );
|
||||||
|
}
|
||||||
DeclaredType declaredType = type.accept(
|
DeclaredType declaredType = type.accept(
|
||||||
new SimpleTypeVisitor6<DeclaredType, Void>() {
|
new SimpleTypeVisitor6<DeclaredType, Void>() {
|
||||||
@Override
|
@Override
|
||||||
@ -57,7 +69,7 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeElement typeElement = declaredType.asElement().accept(
|
return declaredType.asElement().accept(
|
||||||
new SimpleElementVisitor6<TypeElement, Void>() {
|
new SimpleElementVisitor6<TypeElement, Void>() {
|
||||||
@Override
|
@Override
|
||||||
public TypeElement visitType(TypeElement e, Void p) {
|
public TypeElement visitType(TypeElement e, Void p) {
|
||||||
@ -66,30 +78,63 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
return findBuilder( typeElement, elements, types );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TypeMirror findBuilder(TypeElement typeElement, Elements elements, Types types) {
|
protected BuilderInfo findBuilderInfo(TypeElement typeElement, Elements elements, Types types) {
|
||||||
Name name = typeElement.getQualifiedName();
|
if ( shouldIgnore( typeElement ) ) {
|
||||||
if ( name.length() == 0 || JAVA_JAVAX_PACKAGE.matcher( name ).matches() ) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ExecutableElement> methods = ElementFilter.methodsIn( typeElement.getEnclosedElements() );
|
List<ExecutableElement> methods = ElementFilter.methodsIn( typeElement.getEnclosedElements() );
|
||||||
|
|
||||||
for ( ExecutableElement method : methods ) {
|
for ( ExecutableElement method : methods ) {
|
||||||
if ( isBuilderMethod( method ) ) {
|
if ( isPossibleBuilderCreationMethod( method, typeElement, types ) ) {
|
||||||
return method.getReturnType();
|
TypeElement builderElement = getTypeElement( method.getReturnType() );
|
||||||
|
ExecutableElement buildMethod = findBuildMethod( builderElement, typeElement, types );
|
||||||
|
if ( buildMethod != null ) {
|
||||||
|
return new BuilderInfo.Builder()
|
||||||
|
.builderCreationMethod( method )
|
||||||
|
.buildMethod( buildMethod )
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return findBuilderInfo( typeElement.getSuperclass(), elements, types );
|
||||||
|
}
|
||||||
|
|
||||||
return findBuilder( typeElement.getSuperclass(), elements, types );
|
protected boolean isPossibleBuilderCreationMethod(ExecutableElement method, TypeElement typeElement, Types types) {
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isBuilderMethod(ExecutableElement method) {
|
|
||||||
return method.getParameters().isEmpty()
|
return method.getParameters().isEmpty()
|
||||||
&& method.getSimpleName().toString().equals( "builder" )
|
|
||||||
&& method.getModifiers().contains( Modifier.PUBLIC )
|
&& method.getModifiers().contains( Modifier.PUBLIC )
|
||||||
&& method.getModifiers().contains( Modifier.STATIC );
|
&& method.getModifiers().contains( Modifier.STATIC )
|
||||||
|
&& !types.isSameType( method.getReturnType(), typeElement.asType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExecutableElement findBuildMethod(TypeElement builderElement, TypeElement typeElement, Types types) {
|
||||||
|
if ( shouldIgnore( builderElement ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExecutableElement> builderMethods = ElementFilter.methodsIn( builderElement.getEnclosedElements() );
|
||||||
|
for ( ExecutableElement buildMethod : builderMethods ) {
|
||||||
|
if ( isBuildMethod( buildMethod, typeElement, types ) ) {
|
||||||
|
return buildMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return findBuildMethod(
|
||||||
|
getTypeElement( builderElement.getSuperclass() ),
|
||||||
|
typeElement,
|
||||||
|
types
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isBuildMethod(ExecutableElement buildMethod, TypeElement typeElement,
|
||||||
|
Types types) {
|
||||||
|
return buildMethod.getParameters().isEmpty() &&
|
||||||
|
buildMethod.getModifiers().contains( Modifier.PUBLIC )
|
||||||
|
&& types.isAssignable( buildMethod.getReturnType(), typeElement.asType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldIgnore(TypeElement typeElement) {
|
||||||
|
return typeElement == null || JAVA_JAVAX_PACKAGE.matcher( typeElement.getQualifiedName() ).matches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.util;
|
package org.mapstruct.ap.spi;
|
||||||
|
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
@ -78,9 +78,7 @@
|
|||||||
</#list>
|
</#list>
|
||||||
<#if returnType.name != "void">
|
<#if returnType.name != "void">
|
||||||
|
|
||||||
<#if resultType.builderType??>
|
<#if finalizeMethod??>
|
||||||
return ${resultName}.build();
|
|
||||||
<#elseif finalizeMethod??>
|
|
||||||
return ${resultName}.<@includeModel object=finalizeMethod />;
|
return ${resultName}.<@includeModel object=finalizeMethod />;
|
||||||
<#else>
|
<#else>
|
||||||
return ${resultName};
|
return ${resultName};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user