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.AnnotationProcessorContext;
|
||||
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
|
||||
|
@ -40,8 +40,8 @@ import javax.tools.Diagnostic;
|
||||
import org.mapstruct.ap.internal.model.PropertyMapping.ConstantMappingBuilder;
|
||||
import org.mapstruct.ap.internal.model.PropertyMapping.JavaExpressionMappingBuilder;
|
||||
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.ParameterBinding;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer;
|
||||
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer.GraphAnalyzerBuilder;
|
||||
@ -244,33 +244,8 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
( (ForgedMethod) method ).addThrownTypes( factoryMethod.getThrownTypes() );
|
||||
}
|
||||
|
||||
MethodReference finalizeMethod = null;
|
||||
if (
|
||||
!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()
|
||||
);
|
||||
}
|
||||
MethodReference finalizeMethod = getFinalizeMethod(
|
||||
resultType == null ? method.getReturnType() : resultType );
|
||||
|
||||
return new BeanMappingMethod(
|
||||
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.
|
||||
*/
|
||||
|
@ -118,7 +118,7 @@ public class MethodReference extends ModelElement implements Assignment {
|
||||
this.name = method.getName();
|
||||
}
|
||||
|
||||
private MethodReference(String name, Type definingType) {
|
||||
private MethodReference(String name, Type definingType, boolean isStatic) {
|
||||
this.name = name;
|
||||
this.definingType = definingType;
|
||||
this.sourceParameters = Collections.emptyList();
|
||||
@ -130,7 +130,7 @@ public class MethodReference extends ModelElement implements Assignment {
|
||||
this.contextParam = null;
|
||||
this.parameterBindings = Collections.emptyList();
|
||||
this.providingParameter = null;
|
||||
this.isStatic = true;
|
||||
this.isStatic = isStatic;
|
||||
}
|
||||
|
||||
public MapperReference getDeclaringMapper() {
|
||||
@ -335,6 +335,10 @@ public class MethodReference extends ModelElement implements Assignment {
|
||||
}
|
||||
|
||||
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.accessor.Accessor;
|
||||
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.
|
||||
@ -72,7 +73,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
private final ImplementationType implementationType;
|
||||
private final Type componentType;
|
||||
private final Type builderType;
|
||||
private final BuilderType builderType;
|
||||
|
||||
private final String packageName;
|
||||
private final String name;
|
||||
@ -105,7 +106,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
|
||||
TypeMirror typeMirror, TypeElement typeElement,
|
||||
List<Type> typeParameters, ImplementationType implementationType, Type componentType,
|
||||
Type builderType,
|
||||
BuilderInfo builderInfo,
|
||||
String packageName, String name, String qualifiedName,
|
||||
boolean isInterface, boolean isEnumType, boolean isIterableType,
|
||||
boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported) {
|
||||
@ -119,7 +120,6 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
this.typeParameters = typeParameters;
|
||||
this.componentType = componentType;
|
||||
this.implementationType = implementationType;
|
||||
this.builderType = builderType;
|
||||
|
||||
this.packageName = packageName;
|
||||
this.name = name;
|
||||
@ -149,6 +149,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
else {
|
||||
enumConstants = Collections.emptyList();
|
||||
}
|
||||
|
||||
this.builderType = BuilderType.create( builderInfo, this, this.typeFactory, this.typeUtils );
|
||||
}
|
||||
//CHECKSTYLE:ON
|
||||
|
||||
@ -176,12 +178,12 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
return componentType;
|
||||
}
|
||||
|
||||
public Type getBuilderType() {
|
||||
public BuilderType getBuilderType() {
|
||||
return builderType;
|
||||
}
|
||||
|
||||
public Type getMappingType() {
|
||||
return builderType != null ? builderType : this;
|
||||
return builderType != null ? builderType.getBuilder() : this;
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
@ -366,7 +368,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
typeParameters,
|
||||
implementationType,
|
||||
componentType,
|
||||
builderType,
|
||||
builderType == null ? null : builderType.asBuilderInfo(),
|
||||
packageName,
|
||||
name,
|
||||
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.RoundContext;
|
||||
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.spi.AstModifyingAnnotationProcessor;
|
||||
import org.mapstruct.ap.spi.BuilderInfo;
|
||||
import org.mapstruct.ap.spi.BuilderProvider;
|
||||
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.withInitialCapacity;
|
||||
@ -170,7 +171,7 @@ public class TypeFactory {
|
||||
}
|
||||
|
||||
ImplementationType implementationType = getImplementationType( mirror );
|
||||
Type builderType = findBuilder( mirror );
|
||||
BuilderInfo builderInfo = findBuilder( mirror );
|
||||
|
||||
boolean isIterableType = typeUtils.isSubtype( mirror, iterableType );
|
||||
boolean isCollectionType = typeUtils.isSubtype( mirror, collectionType );
|
||||
@ -256,7 +257,7 @@ public class TypeFactory {
|
||||
getTypeParameters( mirror, false ),
|
||||
implementationType,
|
||||
componentType,
|
||||
builderType,
|
||||
builderInfo,
|
||||
packageName,
|
||||
name,
|
||||
qualifiedName,
|
||||
@ -486,9 +487,8 @@ public class TypeFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Type findBuilder(TypeMirror type) {
|
||||
TypeMirror builder = BUILDER_PROVIDER.findBuilder( type, elementUtils, typeUtils );
|
||||
return builder == null ? null : getType( builder );
|
||||
private BuilderInfo findBuilder(TypeMirror type) {
|
||||
return BUILDER_PROVIDER.findBuilderInfo( type, elementUtils, typeUtils );
|
||||
}
|
||||
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
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.VirtualMappingMethod;
|
||||
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.DefaultConversionContext;
|
||||
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.SelectionCriteria;
|
||||
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.Message;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
@ -143,7 +142,7 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
||||
|
||||
if (matchingFactoryMethods.isEmpty()) {
|
||||
return findBuilderFactoryMethod( mappingMethod, targetType );
|
||||
return findBuilderFactoryMethod( targetType );
|
||||
}
|
||||
|
||||
if ( matchingFactoryMethods.size() > 1 ) {
|
||||
@ -166,39 +165,26 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
matchingFactoryMethod.getParameterBindings() );
|
||||
}
|
||||
|
||||
private MethodReference findBuilderFactoryMethod(Method mappingMethod, Type targetType) {
|
||||
if ( targetType.getBuilderType() == null ) {
|
||||
return 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
|
||||
private MethodReference findBuilderFactoryMethod(Type targetType) {
|
||||
BuilderType builder = targetType.getBuilderType();
|
||||
if ( builder == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the default constructor, if it exists, and construct the FactoryMethod
|
||||
// We could also live with assuming it exists
|
||||
ExecutableElement builderCreationMethod = builder.getBuilderCreationMethod();
|
||||
if ( builderCreationMethod.getKind() == ElementKind.CONSTRUCTOR ) {
|
||||
// If the builder creation method is a constructor it would be handled properly down the line
|
||||
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) {
|
||||
for ( MapperReference ref : mapperReferences ) {
|
||||
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.DefaultAccessorNamingStrategy;
|
||||
import org.mapstruct.ap.spi.MethodType;
|
||||
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
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 javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
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.ElementFilter;
|
||||
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?\\..*" );
|
||||
|
||||
@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(
|
||||
new SimpleTypeVisitor6<DeclaredType, Void>() {
|
||||
@Override
|
||||
@ -57,7 +69,7 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeElement typeElement = declaredType.asElement().accept(
|
||||
return declaredType.asElement().accept(
|
||||
new SimpleElementVisitor6<TypeElement, Void>() {
|
||||
@Override
|
||||
public TypeElement visitType(TypeElement e, Void p) {
|
||||
@ -66,30 +78,63 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
return findBuilder( typeElement, elements, types );
|
||||
}
|
||||
|
||||
protected TypeMirror findBuilder(TypeElement typeElement, Elements elements, Types types) {
|
||||
Name name = typeElement.getQualifiedName();
|
||||
if ( name.length() == 0 || JAVA_JAVAX_PACKAGE.matcher( name ).matches() ) {
|
||||
protected BuilderInfo findBuilderInfo(TypeElement typeElement, Elements elements, Types types) {
|
||||
if ( shouldIgnore( typeElement ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ExecutableElement> methods = ElementFilter.methodsIn( typeElement.getEnclosedElements() );
|
||||
|
||||
for ( ExecutableElement method : methods ) {
|
||||
if ( isBuilderMethod( method ) ) {
|
||||
return method.getReturnType();
|
||||
if ( isPossibleBuilderCreationMethod( method, typeElement, types ) ) {
|
||||
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 isBuilderMethod(ExecutableElement method) {
|
||||
protected boolean isPossibleBuilderCreationMethod(ExecutableElement method, TypeElement typeElement, Types types) {
|
||||
return method.getParameters().isEmpty()
|
||||
&& method.getSimpleName().toString().equals( "builder" )
|
||||
&& 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
|
||||
* 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.type.TypeMirror;
|
@ -78,9 +78,7 @@
|
||||
</#list>
|
||||
<#if returnType.name != "void">
|
||||
|
||||
<#if resultType.builderType??>
|
||||
return ${resultName}.build();
|
||||
<#elseif finalizeMethod??>
|
||||
<#if finalizeMethod??>
|
||||
return ${resultName}.<@includeModel object=finalizeMethod />;
|
||||
<#else>
|
||||
return ${resultName};
|
||||
|
Loading…
x
Reference in New Issue
Block a user