mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
* Add new @Builder annotation for defining a build method * When there are multiple build methods look for a method named `build` and if found use it * If @Builder is defined than look for a build method with the defined method * When a type has multiple builder creation methods throw an exception and don't use the builder Defaulting to a method named `build` will make sure that a correct method is selected for: * FreeBuilder - it has two methods: `build` and `buildPartial` * Protobuf - it has three methods: `getDefaultInstanceForType`, `build` and `buildPartial`
This commit is contained in:
parent
62ffa3fa43
commit
ef270caecb
@ -97,4 +97,23 @@ public @interface BeanMapping {
|
|||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
String[] ignoreUnmappedSourceProperties() default {};
|
String[] ignoreUnmappedSourceProperties() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information that should be used for the builder mappings. This can be used to define custom build methods
|
||||||
|
* for the builder strategy that one uses.
|
||||||
|
*
|
||||||
|
* If no builder is defined the builder given via {@link MapperConfig#builder()} or {@link Mapper#builder()}
|
||||||
|
* will be applied.
|
||||||
|
* <p>
|
||||||
|
* NOTE: In case no builder is defined here, in {@link Mapper} or {@link MapperConfig} and there is a single
|
||||||
|
* build method, then that method would be used.
|
||||||
|
* <p>
|
||||||
|
* If the builder is defined and there is a single method that does not match the name of the finisher than
|
||||||
|
* a compile error will occurs
|
||||||
|
*
|
||||||
|
* @return the builder information for the method level
|
||||||
|
*
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
Builder builder() default @Builder;
|
||||||
}
|
}
|
||||||
|
45
core-common/src/main/java/org/mapstruct/Builder.java
Normal file
45
core-common/src/main/java/org/mapstruct/Builder.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.mapstruct.util.Experimental;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of builders, e.g. the name of the final build method.
|
||||||
|
*
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({})
|
||||||
|
@Experimental
|
||||||
|
public @interface Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the build method that needs to be invoked on the builder to create the type being build
|
||||||
|
*
|
||||||
|
* @return the method that needs to tbe invoked on the builder
|
||||||
|
*/
|
||||||
|
String buildMethod() default "build";
|
||||||
|
}
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct;
|
package org.mapstruct;
|
||||||
|
|
||||||
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@ -27,6 +25,8 @@ import java.lang.annotation.Target;
|
|||||||
|
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks an interface or abstract class as a mapper and activates the generation of a implementation of that type via
|
* Marks an interface or abstract class as a mapper and activates the generation of a implementation of that type via
|
||||||
* MapStruct.
|
* MapStruct.
|
||||||
@ -200,4 +200,22 @@ public @interface Mapper {
|
|||||||
*/
|
*/
|
||||||
boolean disableSubMappingMethodsGeneration() default false;
|
boolean disableSubMappingMethodsGeneration() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information that should be used for the builder mappings. This can be used to define custom build methods
|
||||||
|
* for the builder strategy that one uses.
|
||||||
|
*
|
||||||
|
* If no builder is defined the builder given via {@link MapperConfig#builder()} will be applied.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* NOTE: In case no builder is defined here, in {@link BeanMapping} or {@link MapperConfig} and there is a single
|
||||||
|
* build method, then that method would be used.
|
||||||
|
* <p>
|
||||||
|
* If the builder is defined and there is a single method that does not match the name of the finisher than
|
||||||
|
* a compile error will occurs
|
||||||
|
*
|
||||||
|
* @return the builder information
|
||||||
|
*
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
Builder builder() default @Builder;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct;
|
package org.mapstruct;
|
||||||
|
|
||||||
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@ -27,6 +25,8 @@ import java.lang.annotation.Target;
|
|||||||
|
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks a class or interface as configuration source for generated mappers. This allows to share common configurations
|
* Marks a class or interface as configuration source for generated mappers. This allows to share common configurations
|
||||||
* between several mapper classes.
|
* between several mapper classes.
|
||||||
@ -186,4 +186,24 @@ public @interface MapperConfig {
|
|||||||
* @since 1.2
|
* @since 1.2
|
||||||
*/
|
*/
|
||||||
boolean disableSubMappingMethodsGeneration() default false;
|
boolean disableSubMappingMethodsGeneration() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information that should be used for the builder mappings. This can be used to define custom build methods
|
||||||
|
* for the builder strategy that one uses.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Can be overridden by {@link MapperConfig#builder()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* NOTE: In case no builder is defined here, in {@link BeanMapping} or {@link Mapper} and there is a single
|
||||||
|
* build method, then that method would be used.
|
||||||
|
* <p>
|
||||||
|
* If the builder is defined and there is a single method that does not match the name of the finisher than
|
||||||
|
* a compile error will occurs
|
||||||
|
*
|
||||||
|
* @return the builder information
|
||||||
|
*
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
Builder builder() default @Builder;
|
||||||
}
|
}
|
||||||
|
@ -639,6 +639,12 @@ The default implementation of the `BuilderProvider` assumes the following:
|
|||||||
So for example `Person` has a public static method that returns `PersonBuilder`.
|
So for example `Person` has a public static method that returns `PersonBuilder`.
|
||||||
* The builder type has a parameterless public method (build method) that returns the type being build
|
* The builder type has a parameterless public method (build method) that returns the type being build
|
||||||
In our example `PersonBuilder` has a method returning `Person`.
|
In our example `PersonBuilder` has a method returning `Person`.
|
||||||
|
* In case there are multiple build methods, MapStruct will look for a method called `build` if such methods exists
|
||||||
|
than this would be used, otherwise a compilation error would be created.
|
||||||
|
* A specific build method can be defined by using `@Builder` within: `@BeanMapping`, `@Mapper` or `@MapperConfig`
|
||||||
|
* In case there are multiple builder creation methods that satisfy the above conditions then a `MoreThanOneBuilderCreationMethodException`
|
||||||
|
will be thrown from the `DefaultBuilderProvider` SPI.
|
||||||
|
In case of a `MoreThanOneBuilderCreationMethodException` MapStruct will write a warning in the compilation and not use any builder.
|
||||||
|
|
||||||
If such type is found then MapStruct will use that type to perform the mapping to (i.e. it will look for setters into that type).
|
If such type is found then MapStruct will use that type to perform the mapping to (i.e. it will look for setters into that type).
|
||||||
To finish the mapping MapStruct generates code that will invoke the build method of the builder.
|
To finish the mapping MapStruct generates code that will invoke the build method of the builder.
|
||||||
|
@ -287,7 +287,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MethodReference.forMethodCall( builderType.getBuildMethod() );
|
return BuilderFinisherMethodResolver.getBuilderFinisherMethod( method, builderType, ctx );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
|
import org.mapstruct.ap.internal.model.source.BeanMapping;
|
||||||
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
|
import org.mapstruct.ap.internal.prism.BuilderPrism;
|
||||||
|
import org.mapstruct.ap.internal.util.MapperConfiguration;
|
||||||
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class BuilderFinisherMethodResolver {
|
||||||
|
|
||||||
|
private static final String DEFAULT_BUILD_METHOD_NAME = "build";
|
||||||
|
|
||||||
|
private BuilderFinisherMethodResolver() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodReference getBuilderFinisherMethod(Method method, BuilderType builderType,
|
||||||
|
MappingBuilderContext ctx) {
|
||||||
|
Collection<ExecutableElement> buildMethods = builderType.getBuildMethods();
|
||||||
|
if ( buildMethods.isEmpty() ) {
|
||||||
|
//If we reach this method this should never happen
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderPrism builderMapping = builderMappingPrism( method, ctx );
|
||||||
|
if ( builderMapping == null && buildMethods.size() == 1 ) {
|
||||||
|
return MethodReference.forMethodCall( first( buildMethods ).getSimpleName().toString() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String buildMethodPattern = DEFAULT_BUILD_METHOD_NAME;
|
||||||
|
if ( builderMapping != null ) {
|
||||||
|
buildMethodPattern = builderMapping.buildMethod();
|
||||||
|
}
|
||||||
|
for ( ExecutableElement buildMethod : buildMethods ) {
|
||||||
|
String methodName = buildMethod.getSimpleName().toString();
|
||||||
|
if ( methodName.matches( buildMethodPattern ) ) {
|
||||||
|
return MethodReference.forMethodCall( methodName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( builderMapping == null ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
method.getExecutable(),
|
||||||
|
Message.BUILDER_NO_BUILD_METHOD_FOUND_DEFAULT,
|
||||||
|
buildMethodPattern,
|
||||||
|
builderType.getBuilder(),
|
||||||
|
builderType.getBuildingType(),
|
||||||
|
Strings.join( buildMethods, ", " )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
method.getExecutable(),
|
||||||
|
builderMapping.mirror,
|
||||||
|
Message.BUILDER_NO_BUILD_METHOD_FOUND,
|
||||||
|
buildMethodPattern,
|
||||||
|
builderType.getBuilder(),
|
||||||
|
builderType.getBuildingType(),
|
||||||
|
Strings.join( buildMethods, ", " )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BuilderPrism builderMappingPrism(Method method, MappingBuilderContext ctx) {
|
||||||
|
BeanMapping beanMapping = method.getMappingOptions().getBeanMapping();
|
||||||
|
if ( beanMapping != null && beanMapping.getBuilder() != null ) {
|
||||||
|
return beanMapping.getBuilder();
|
||||||
|
}
|
||||||
|
return MapperConfiguration.getInstanceOn( ctx.getMapperTypeElement() ).getBuilderPrism();
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model.common;
|
package org.mapstruct.ap.internal.model.common;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
@ -33,20 +34,20 @@ public class BuilderType {
|
|||||||
private final Type owningType;
|
private final Type owningType;
|
||||||
private final Type buildingType;
|
private final Type buildingType;
|
||||||
private final ExecutableElement builderCreationMethod;
|
private final ExecutableElement builderCreationMethod;
|
||||||
private final ExecutableElement buildMethod;
|
private final Collection<ExecutableElement> buildMethods;
|
||||||
|
|
||||||
private BuilderType(
|
private BuilderType(
|
||||||
Type builder,
|
Type builder,
|
||||||
Type owningType,
|
Type owningType,
|
||||||
Type buildingType,
|
Type buildingType,
|
||||||
ExecutableElement builderCreationMethod,
|
ExecutableElement builderCreationMethod,
|
||||||
ExecutableElement buildMethod
|
Collection<ExecutableElement> buildMethods
|
||||||
) {
|
) {
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
this.owningType = owningType;
|
this.owningType = owningType;
|
||||||
this.buildingType = buildingType;
|
this.buildingType = buildingType;
|
||||||
this.builderCreationMethod = builderCreationMethod;
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
this.buildMethod = buildMethod;
|
this.buildMethods = buildMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,18 +88,17 @@ public class BuilderType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the method that needs to be invoked on the builder to create the type being built.
|
* The build methods that can be invoked to create the type being built.
|
||||||
*
|
* @return the build methods that can be invoked to create the type being built
|
||||||
* @return the name of the method that needs to be invoked on the type that is being built
|
|
||||||
*/
|
*/
|
||||||
public String getBuildMethod() {
|
public Collection<ExecutableElement> getBuildMethods() {
|
||||||
return buildMethod.getSimpleName().toString();
|
return buildMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BuilderInfo asBuilderInfo() {
|
public BuilderInfo asBuilderInfo() {
|
||||||
return new BuilderInfo.Builder()
|
return new BuilderInfo.Builder()
|
||||||
.builderCreationMethod( this.builderCreationMethod )
|
.builderCreationMethod( this.builderCreationMethod )
|
||||||
.buildMethod( this.buildMethod )
|
.buildMethod( this.buildMethods )
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +107,6 @@ public class BuilderType {
|
|||||||
if ( builderInfo == null ) {
|
if ( builderInfo == null ) {
|
||||||
return 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() );
|
Type builder = typeFactory.getType( builderInfo.getBuilderCreationMethod().getReturnType() );
|
||||||
ExecutableElement builderCreationMethod = builderInfo.getBuilderCreationMethod();
|
ExecutableElement builderCreationMethod = builderInfo.getBuilderCreationMethod();
|
||||||
@ -133,7 +128,7 @@ public class BuilderType {
|
|||||||
owner,
|
owner,
|
||||||
typeToBuild,
|
typeToBuild,
|
||||||
builderCreationMethod,
|
builderCreationMethod,
|
||||||
buildMethod
|
builderInfo.getBuildMethods()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,11 +55,16 @@ import javax.lang.model.util.Types;
|
|||||||
|
|
||||||
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
||||||
import org.mapstruct.ap.internal.util.Collections;
|
import org.mapstruct.ap.internal.util.Collections;
|
||||||
|
import org.mapstruct.ap.internal.util.Extractor;
|
||||||
|
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||||
import org.mapstruct.ap.internal.util.JavaStreamConstants;
|
import org.mapstruct.ap.internal.util.JavaStreamConstants;
|
||||||
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
import org.mapstruct.ap.internal.util.RoundContext;
|
import org.mapstruct.ap.internal.util.RoundContext;
|
||||||
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
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.BuilderInfo;
|
||||||
|
import org.mapstruct.ap.spi.MoreThanOneBuilderCreationMethodException;
|
||||||
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
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;
|
||||||
@ -73,8 +78,17 @@ import static org.mapstruct.ap.internal.model.common.ImplementationType.withLoad
|
|||||||
*/
|
*/
|
||||||
public class TypeFactory {
|
public class TypeFactory {
|
||||||
|
|
||||||
|
private static final Extractor<BuilderInfo, String> BUILDER_INFO_CREATION_METHOD_EXTRACTOR =
|
||||||
|
new Extractor<BuilderInfo, String>() {
|
||||||
|
@Override
|
||||||
|
public String apply(BuilderInfo builderInfo) {
|
||||||
|
return builderInfo.getBuilderCreationMethod().toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final Elements elementUtils;
|
private final Elements elementUtils;
|
||||||
private final Types typeUtils;
|
private final Types typeUtils;
|
||||||
|
private final FormattingMessager messager;
|
||||||
private final RoundContext roundContext;
|
private final RoundContext roundContext;
|
||||||
|
|
||||||
private final TypeMirror iterableType;
|
private final TypeMirror iterableType;
|
||||||
@ -85,9 +99,10 @@ public class TypeFactory {
|
|||||||
private final Map<String, ImplementationType> implementationTypes = new HashMap<String, ImplementationType>();
|
private final Map<String, ImplementationType> implementationTypes = new HashMap<String, ImplementationType>();
|
||||||
private final Map<String, String> importedQualifiedTypesBySimpleName = new HashMap<String, String>();
|
private final Map<String, String> importedQualifiedTypesBySimpleName = new HashMap<String, String>();
|
||||||
|
|
||||||
public TypeFactory(Elements elementUtils, Types typeUtils, RoundContext roundContext) {
|
public TypeFactory(Elements elementUtils, Types typeUtils, FormattingMessager messager, RoundContext roundContext) {
|
||||||
this.elementUtils = elementUtils;
|
this.elementUtils = elementUtils;
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
|
this.messager = messager;
|
||||||
this.roundContext = roundContext;
|
this.roundContext = roundContext;
|
||||||
|
|
||||||
iterableType = typeUtils.erasure( elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType() );
|
iterableType = typeUtils.erasure( elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType() );
|
||||||
@ -502,10 +517,22 @@ public class TypeFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BuilderInfo findBuilder(TypeMirror type) {
|
private BuilderInfo findBuilder(TypeMirror type) {
|
||||||
|
try {
|
||||||
return roundContext.getAnnotationProcessorContext()
|
return roundContext.getAnnotationProcessorContext()
|
||||||
.getBuilderProvider()
|
.getBuilderProvider()
|
||||||
.findBuilderInfo( type, elementUtils, typeUtils );
|
.findBuilderInfo( type, elementUtils, typeUtils );
|
||||||
}
|
}
|
||||||
|
catch ( MoreThanOneBuilderCreationMethodException ex ) {
|
||||||
|
messager.printMessage(
|
||||||
|
typeUtils.asElement( type ),
|
||||||
|
Message.BUILDER_MORE_THAN_ONE_BUILDER_CREATION_METHOD,
|
||||||
|
type,
|
||||||
|
Strings.join( ex.getBuilderInfo(), ", ", BUILDER_INFO_CREATION_METHOD_EXTRACTOR )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private TypeMirror getComponentType(TypeMirror mirror) {
|
private TypeMirror getComponentType(TypeMirror mirror) {
|
||||||
if ( mirror.getKind() != TypeKind.ARRAY ) {
|
if ( mirror.getKind() != TypeKind.ARRAY ) {
|
||||||
|
@ -25,6 +25,7 @@ import javax.lang.model.type.TypeKind;
|
|||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.prism.BeanMappingPrism;
|
import org.mapstruct.ap.internal.prism.BeanMappingPrism;
|
||||||
|
import org.mapstruct.ap.internal.prism.BuilderPrism;
|
||||||
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.prism.ReportingPolicyPrism;
|
import org.mapstruct.ap.internal.prism.ReportingPolicyPrism;
|
||||||
import org.mapstruct.ap.internal.util.FormattingMessager;
|
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||||
@ -42,6 +43,7 @@ public class BeanMapping {
|
|||||||
private final ReportingPolicyPrism reportingPolicy;
|
private final ReportingPolicyPrism reportingPolicy;
|
||||||
private final boolean ignoreByDefault;
|
private final boolean ignoreByDefault;
|
||||||
private final List<String> ignoreUnmappedSourceProperties;
|
private final List<String> ignoreUnmappedSourceProperties;
|
||||||
|
private final BuilderPrism builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a mapping for inheritance. Will set ignoreByDefault to false.
|
* creates a mapping for inheritance. Will set ignoreByDefault to false.
|
||||||
@ -55,7 +57,8 @@ public class BeanMapping {
|
|||||||
map.nullValueMappingStrategy,
|
map.nullValueMappingStrategy,
|
||||||
map.reportingPolicy,
|
map.reportingPolicy,
|
||||||
false,
|
false,
|
||||||
map.ignoreUnmappedSourceProperties
|
map.ignoreUnmappedSourceProperties,
|
||||||
|
map.builder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +77,15 @@ public class BeanMapping {
|
|||||||
: NullValueMappingStrategyPrism.valueOf( beanMapping.nullValueMappingStrategy() );
|
: NullValueMappingStrategyPrism.valueOf( beanMapping.nullValueMappingStrategy() );
|
||||||
|
|
||||||
boolean ignoreByDefault = beanMapping.ignoreByDefault();
|
boolean ignoreByDefault = beanMapping.ignoreByDefault();
|
||||||
|
BuilderPrism builderMapping = null;
|
||||||
|
if ( beanMapping.values.builder() != null ) {
|
||||||
|
builderMapping = beanMapping.builder();
|
||||||
|
}
|
||||||
|
|
||||||
if ( !resultTypeIsDefined && beanMapping.qualifiedBy().isEmpty() && beanMapping.qualifiedByName().isEmpty()
|
if ( !resultTypeIsDefined && beanMapping.qualifiedBy().isEmpty() && beanMapping.qualifiedByName().isEmpty()
|
||||||
&& beanMapping.ignoreUnmappedSourceProperties().isEmpty()
|
&& beanMapping.ignoreUnmappedSourceProperties().isEmpty()
|
||||||
&& ( nullValueMappingStrategy == null ) && !ignoreByDefault ) {
|
&& ( nullValueMappingStrategy == null ) && !ignoreByDefault
|
||||||
|
&& builderMapping == null ) {
|
||||||
|
|
||||||
messager.printMessage( method, Message.BEANMAPPING_NO_ELEMENTS );
|
messager.printMessage( method, Message.BEANMAPPING_NO_ELEMENTS );
|
||||||
}
|
}
|
||||||
@ -94,7 +103,8 @@ public class BeanMapping {
|
|||||||
nullValueMappingStrategy,
|
nullValueMappingStrategy,
|
||||||
null,
|
null,
|
||||||
ignoreByDefault,
|
ignoreByDefault,
|
||||||
beanMapping.ignoreUnmappedSourceProperties()
|
beanMapping.ignoreUnmappedSourceProperties(),
|
||||||
|
builderMapping
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,17 +115,18 @@ public class BeanMapping {
|
|||||||
* @return bean mapping that needs to be used for Mappings
|
* @return bean mapping that needs to be used for Mappings
|
||||||
*/
|
*/
|
||||||
public static BeanMapping forForgedMethods() {
|
public static BeanMapping forForgedMethods() {
|
||||||
return new BeanMapping( null, null, ReportingPolicyPrism.IGNORE, false, Collections.<String>emptyList() );
|
return new BeanMapping( null, null, ReportingPolicyPrism.IGNORE, false, Collections.<String>emptyList(), null );
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeanMapping(SelectionParameters selectionParameters, NullValueMappingStrategyPrism nvms,
|
private BeanMapping(SelectionParameters selectionParameters, NullValueMappingStrategyPrism nvms,
|
||||||
ReportingPolicyPrism reportingPolicy, boolean ignoreByDefault,
|
ReportingPolicyPrism reportingPolicy, boolean ignoreByDefault,
|
||||||
List<String> ignoreUnmappedSourceProperties) {
|
List<String> ignoreUnmappedSourceProperties, BuilderPrism builder) {
|
||||||
this.selectionParameters = selectionParameters;
|
this.selectionParameters = selectionParameters;
|
||||||
this.nullValueMappingStrategy = nvms;
|
this.nullValueMappingStrategy = nvms;
|
||||||
this.reportingPolicy = reportingPolicy;
|
this.reportingPolicy = reportingPolicy;
|
||||||
this.ignoreByDefault = ignoreByDefault;
|
this.ignoreByDefault = ignoreByDefault;
|
||||||
this.ignoreUnmappedSourceProperties = ignoreUnmappedSourceProperties;
|
this.ignoreUnmappedSourceProperties = ignoreUnmappedSourceProperties;
|
||||||
|
this.builder = builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SelectionParameters getSelectionParameters() {
|
public SelectionParameters getSelectionParameters() {
|
||||||
@ -137,4 +148,8 @@ public class BeanMapping {
|
|||||||
public List<String> getIgnoreUnmappedSourceProperties() {
|
public List<String> getIgnoreUnmappedSourceProperties() {
|
||||||
return ignoreUnmappedSourceProperties;
|
return ignoreUnmappedSourceProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuilderPrism getBuilder() {
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlElementRef;
|
|||||||
import org.mapstruct.AfterMapping;
|
import org.mapstruct.AfterMapping;
|
||||||
import org.mapstruct.BeanMapping;
|
import org.mapstruct.BeanMapping;
|
||||||
import org.mapstruct.BeforeMapping;
|
import org.mapstruct.BeforeMapping;
|
||||||
|
import org.mapstruct.Builder;
|
||||||
import org.mapstruct.Context;
|
import org.mapstruct.Context;
|
||||||
import org.mapstruct.DecoratedWith;
|
import org.mapstruct.DecoratedWith;
|
||||||
import org.mapstruct.InheritConfiguration;
|
import org.mapstruct.InheritConfiguration;
|
||||||
@ -71,6 +72,7 @@ import net.java.dev.hickory.prism.GeneratePrisms;
|
|||||||
@GeneratePrism(value = ValueMapping.class, publicAccess = true),
|
@GeneratePrism(value = ValueMapping.class, publicAccess = true),
|
||||||
@GeneratePrism(value = ValueMappings.class, publicAccess = true),
|
@GeneratePrism(value = ValueMappings.class, publicAccess = true),
|
||||||
@GeneratePrism(value = Context.class, publicAccess = true),
|
@GeneratePrism(value = Context.class, publicAccess = true),
|
||||||
|
@GeneratePrism(value = Builder.class, publicAccess = true),
|
||||||
|
|
||||||
// external types
|
// external types
|
||||||
@GeneratePrism(value = XmlElementDecl.class, publicAccess = true),
|
@GeneratePrism(value = XmlElementDecl.class, publicAccess = true),
|
||||||
|
@ -64,6 +64,7 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
|
|||||||
this.typeFactory = new TypeFactory(
|
this.typeFactory = new TypeFactory(
|
||||||
processingEnvironment.getElementUtils(),
|
processingEnvironment.getElementUtils(),
|
||||||
delegatingTypes,
|
delegatingTypes,
|
||||||
|
messager,
|
||||||
roundContext
|
roundContext
|
||||||
);
|
);
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
@ -28,6 +28,7 @@ import javax.lang.model.type.DeclaredType;
|
|||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.option.Options;
|
import org.mapstruct.ap.internal.option.Options;
|
||||||
|
import org.mapstruct.ap.internal.prism.BuilderPrism;
|
||||||
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
|
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.prism.InjectionStrategyPrism;
|
import org.mapstruct.ap.internal.prism.InjectionStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.prism.MapperConfigPrism;
|
import org.mapstruct.ap.internal.prism.MapperConfigPrism;
|
||||||
@ -238,6 +239,18 @@ public class MapperConfiguration {
|
|||||||
return mapperPrism.disableSubMappingMethodsGeneration(); // fall back to default defined in the annotation
|
return mapperPrism.disableSubMappingMethodsGeneration(); // fall back to default defined in the annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuilderPrism getBuilderPrism() {
|
||||||
|
if ( mapperPrism.values.builder() != null ) {
|
||||||
|
return mapperPrism.builder();
|
||||||
|
}
|
||||||
|
else if ( mapperConfigPrism != null && mapperConfigPrism.values.builder() != null ) {
|
||||||
|
return mapperConfigPrism.builder();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DeclaredType config() {
|
public DeclaredType config() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,10 @@ public enum Message {
|
|||||||
GENERAL_NOT_ALL_FORGED_CREATED( "Internal Error in creation of Forged Methods, it was expected all Forged Methods to finished with creation, but %s did not" ),
|
GENERAL_NOT_ALL_FORGED_CREATED( "Internal Error in creation of Forged Methods, it was expected all Forged Methods to finished with creation, but %s did not" ),
|
||||||
GENERAL_NO_SUITABLE_CONSTRUCTOR( "%s does not have an accessible parameterless constructor." ),
|
GENERAL_NO_SUITABLE_CONSTRUCTOR( "%s does not have an accessible parameterless constructor." ),
|
||||||
|
|
||||||
|
BUILDER_MORE_THAN_ONE_BUILDER_CREATION_METHOD( "More than one builder creation method for \"%s\". Found methods: \"%s\". Builder will not be used. Consider implementing a custom BuilderProvider SPI.", Diagnostic.Kind.WARNING ),
|
||||||
|
BUILDER_NO_BUILD_METHOD_FOUND("No build method \"%s\" found in \"%s\" for \"%s\". Found methods: \"%s\".", Diagnostic.Kind.ERROR ),
|
||||||
|
BUILDER_NO_BUILD_METHOD_FOUND_DEFAULT("No build method \"%s\" found in \"%s\" for \"%s\". Found methods: \"%s\". Consider to add @Builder in order to select the correct build method.", Diagnostic.Kind.ERROR ),
|
||||||
|
|
||||||
RETRIEVAL_NO_INPUT_ARGS( "Can't generate mapping method with no input arguments." ),
|
RETRIEVAL_NO_INPUT_ARGS( "Can't generate mapping method with no input arguments." ),
|
||||||
RETRIEVAL_DUPLICATE_MAPPING_TARGETS( "Can't generate mapping method with more than one @MappingTarget parameter." ),
|
RETRIEVAL_DUPLICATE_MAPPING_TARGETS( "Can't generate mapping method with more than one @MappingTarget parameter." ),
|
||||||
RETRIEVAL_VOID_MAPPING_METHOD( "Can't generate mapping method with return type void." ),
|
RETRIEVAL_VOID_MAPPING_METHOD( "Can't generate mapping method with return type void." ),
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.spi;
|
package org.mapstruct.ap.spi;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,11 +29,11 @@ import javax.lang.model.element.ExecutableElement;
|
|||||||
public class BuilderInfo {
|
public class BuilderInfo {
|
||||||
|
|
||||||
private final ExecutableElement builderCreationMethod;
|
private final ExecutableElement builderCreationMethod;
|
||||||
private final ExecutableElement buildMethod;
|
private final Collection<ExecutableElement> buildMethods;
|
||||||
|
|
||||||
private BuilderInfo(ExecutableElement builderCreationMethod, ExecutableElement buildMethod) {
|
private BuilderInfo(ExecutableElement builderCreationMethod, Collection<ExecutableElement> buildMethods) {
|
||||||
this.builderCreationMethod = builderCreationMethod;
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
this.buildMethod = buildMethod;
|
this.buildMethods = buildMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,18 +51,18 @@ public class BuilderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method that can be used to build the type being built.
|
* The methods that can be used to build the type being built.
|
||||||
* This should be a {@code public} method within the builder itself
|
* This should be {@code public} methods within the builder itself
|
||||||
*
|
*
|
||||||
* @return the build method for the type
|
* @return the build method for the type
|
||||||
*/
|
*/
|
||||||
public ExecutableElement getBuildMethod() {
|
public Collection<ExecutableElement> getBuildMethods() {
|
||||||
return buildMethod;
|
return buildMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private ExecutableElement builderCreationMethod;
|
private ExecutableElement builderCreationMethod;
|
||||||
private ExecutableElement buildMethod;
|
private Collection<ExecutableElement> buildMethods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see BuilderInfo#getBuilderCreationMethod()
|
* @see BuilderInfo#getBuilderCreationMethod()
|
||||||
@ -72,10 +73,10 @@ public class BuilderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see BuilderInfo#getBuildMethod()
|
* @see BuilderInfo#getBuildMethods()
|
||||||
*/
|
*/
|
||||||
public Builder buildMethod(ExecutableElement method) {
|
public Builder buildMethod(Collection<ExecutableElement> methods) {
|
||||||
this.buildMethod = method;
|
this.buildMethods = methods;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +88,13 @@ public class BuilderInfo {
|
|||||||
if ( builderCreationMethod == null ) {
|
if ( builderCreationMethod == null ) {
|
||||||
throw new IllegalArgumentException( "Builder creation method is mandatory" );
|
throw new IllegalArgumentException( "Builder creation method is mandatory" );
|
||||||
}
|
}
|
||||||
else if ( buildMethod == null ) {
|
else if ( buildMethods == null ) {
|
||||||
throw new IllegalArgumentException( "Build method is mandatory" );
|
throw new IllegalArgumentException( "Build methods are mandatory" );
|
||||||
}
|
}
|
||||||
return new BuilderInfo( builderCreationMethod, buildMethod );
|
else if ( buildMethods.isEmpty() ) {
|
||||||
|
throw new IllegalArgumentException( "Build methods must not be empty" );
|
||||||
|
}
|
||||||
|
return new BuilderInfo( builderCreationMethod, buildMethods );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ public interface BuilderProvider {
|
|||||||
*
|
*
|
||||||
* @throws TypeHierarchyErroneousException if the type that needs to be visited is not ready yet, this signals the
|
* @throws TypeHierarchyErroneousException if the type that needs to be visited is not ready yet, this signals the
|
||||||
* MapStruct processor to postpone the generation of the mappers to the next round
|
* MapStruct processor to postpone the generation of the mappers to the next round
|
||||||
|
* @throws MoreThanOneBuilderCreationMethodException if {@code type} has more than one method that can create the
|
||||||
|
* builder
|
||||||
*/
|
*/
|
||||||
BuilderInfo findBuilderInfo(TypeMirror type, Elements elements, Types types);
|
BuilderInfo findBuilderInfo(TypeMirror type, Elements elements, Types types);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.spi;
|
package org.mapstruct.ap.spi;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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;
|
||||||
@ -141,17 +144,22 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
* <p>
|
* <p>
|
||||||
* The default implementation iterates over all the methods in {@code typeElement} and uses
|
* The default implementation iterates over all the methods in {@code typeElement} and uses
|
||||||
* {@link DefaultBuilderProvider#isPossibleBuilderCreationMethod(ExecutableElement, TypeElement, Types)} and
|
* {@link DefaultBuilderProvider#isPossibleBuilderCreationMethod(ExecutableElement, TypeElement, Types)} and
|
||||||
* {@link DefaultBuilderProvider#findBuildMethod(TypeElement, TypeElement, Types)} to create the
|
* {@link DefaultBuilderProvider#findBuildMethods(TypeElement, TypeElement, Types)} to create the
|
||||||
* {@link BuilderInfo}.
|
* {@link BuilderInfo}.
|
||||||
* <p>
|
* <p>
|
||||||
* The default implementation uses {@link DefaultBuilderProvider#shouldIgnore(TypeElement)} to check if the
|
* The default implementation uses {@link DefaultBuilderProvider#shouldIgnore(TypeElement)} to check if the
|
||||||
* {@code typeElement} should be ignored.
|
* {@code typeElement} should be ignored.
|
||||||
|
* <p>
|
||||||
|
* In case there are multiple {@link BuilderInfo} then a {@link MoreThanOneBuilderCreationMethodException} is
|
||||||
|
* thrown.
|
||||||
*
|
*
|
||||||
* @param typeElement the type element for which a builder searched
|
* @param typeElement the type element for which a builder searched
|
||||||
* @param elements the util elements that can be used for operating on the type element
|
* @param elements the util elements that can be used for operating on the type element
|
||||||
* @param types the util types that can be used for operation on {@link TypeMirror}(s)
|
* @param types the util types that can be used for operation on {@link TypeMirror}(s)
|
||||||
*
|
*
|
||||||
* @return the {@link BuilderInfo} or {@code null} if no builder was found for the type
|
* @return the {@link BuilderInfo} or {@code null} if no builder was found for the type
|
||||||
|
* {@link DefaultBuilderProvider#findBuildMethods(TypeElement, TypeElement, Types)}
|
||||||
|
* @throws MoreThanOneBuilderCreationMethodException if there are multiple builder creation methods
|
||||||
*/
|
*/
|
||||||
protected BuilderInfo findBuilderInfo(TypeElement typeElement, Elements elements, Types types) {
|
protected BuilderInfo findBuilderInfo(TypeElement typeElement, Elements elements, Types types) {
|
||||||
if ( shouldIgnore( typeElement ) ) {
|
if ( shouldIgnore( typeElement ) ) {
|
||||||
@ -159,18 +167,28 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ExecutableElement> methods = ElementFilter.methodsIn( typeElement.getEnclosedElements() );
|
List<ExecutableElement> methods = ElementFilter.methodsIn( typeElement.getEnclosedElements() );
|
||||||
|
List<BuilderInfo> builderInfo = new ArrayList<BuilderInfo>();
|
||||||
for ( ExecutableElement method : methods ) {
|
for ( ExecutableElement method : methods ) {
|
||||||
if ( isPossibleBuilderCreationMethod( method, typeElement, types ) ) {
|
if ( isPossibleBuilderCreationMethod( method, typeElement, types ) ) {
|
||||||
TypeElement builderElement = getTypeElement( method.getReturnType() );
|
TypeElement builderElement = getTypeElement( method.getReturnType() );
|
||||||
ExecutableElement buildMethod = findBuildMethod( builderElement, typeElement, types );
|
Collection<ExecutableElement> buildMethods = findBuildMethods( builderElement, typeElement, types );
|
||||||
if ( buildMethod != null ) {
|
if ( !buildMethods.isEmpty() ) {
|
||||||
return new BuilderInfo.Builder()
|
builderInfo.add( new BuilderInfo.Builder()
|
||||||
.builderCreationMethod( method )
|
.builderCreationMethod( method )
|
||||||
.buildMethod( buildMethod )
|
.buildMethod( buildMethods )
|
||||||
.build();
|
.build()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( builderInfo.size() == 1 ) {
|
||||||
|
return builderInfo.get( 0 );
|
||||||
|
}
|
||||||
|
else if ( builderInfo.size() > 1 ) {
|
||||||
|
throw new MoreThanOneBuilderCreationMethodException( typeElement.asType(), builderInfo );
|
||||||
|
}
|
||||||
|
|
||||||
return findBuilderInfo( typeElement.getSuperclass(), elements, types );
|
return findBuilderInfo( typeElement.getSuperclass(), elements, types );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,32 +225,42 @@ public class DefaultBuilderProvider implements BuilderProvider {
|
|||||||
* <p>
|
* <p>
|
||||||
* The default implementation uses {@link DefaultBuilderProvider#shouldIgnore(TypeElement)} to check if the
|
* The default implementation uses {@link DefaultBuilderProvider#shouldIgnore(TypeElement)} to check if the
|
||||||
* {@code builderElement} should be ignored, i.e. not checked for build elements.
|
* {@code builderElement} should be ignored, i.e. not checked for build elements.
|
||||||
*
|
* <p>
|
||||||
|
* If there are multiple methods that satisfy
|
||||||
|
* {@link DefaultBuilderProvider#isBuildMethod(ExecutableElement, TypeElement, Types)} and one of those methods
|
||||||
|
* is names {@code build} that that method would be considered as a build method.
|
||||||
* @param builderElement the element for the builder
|
* @param builderElement the element for the builder
|
||||||
* @param typeElement the element for the type that is being built
|
* @param typeElement the element for the type that is being built
|
||||||
* @param types the util types tat can be used for operations on {@link TypeMirror}(s)
|
* @param types the util types tat can be used for operations on {@link TypeMirror}(s)
|
||||||
*
|
*
|
||||||
* @return the build method for the {@code typeElement} if it exists, or {@code null} if it does not
|
* @return the build method for the {@code typeElement} if it exists, or {@code null} if it does not
|
||||||
|
* {@code build}
|
||||||
*/
|
*/
|
||||||
protected ExecutableElement findBuildMethod(TypeElement builderElement, TypeElement typeElement, Types types) {
|
protected Collection<ExecutableElement> findBuildMethods(TypeElement builderElement, TypeElement typeElement,
|
||||||
|
Types types) {
|
||||||
if ( shouldIgnore( builderElement ) ) {
|
if ( shouldIgnore( builderElement ) ) {
|
||||||
return null;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ExecutableElement> builderMethods = ElementFilter.methodsIn( builderElement.getEnclosedElements() );
|
List<ExecutableElement> builderMethods = ElementFilter.methodsIn( builderElement.getEnclosedElements() );
|
||||||
|
List<ExecutableElement> buildMethods = new ArrayList<ExecutableElement>();
|
||||||
for ( ExecutableElement buildMethod : builderMethods ) {
|
for ( ExecutableElement buildMethod : builderMethods ) {
|
||||||
if ( isBuildMethod( buildMethod, typeElement, types ) ) {
|
if ( isBuildMethod( buildMethod, typeElement, types ) ) {
|
||||||
return buildMethod;
|
buildMethods.add( buildMethod );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return findBuildMethod(
|
if ( buildMethods.isEmpty() ) {
|
||||||
|
return findBuildMethods(
|
||||||
getTypeElement( builderElement.getSuperclass() ),
|
getTypeElement( builderElement.getSuperclass() ),
|
||||||
typeElement,
|
typeElement,
|
||||||
types
|
types
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return buildMethods;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the {@code buildMethod} is a method that creates {@code typeElement}.
|
* Checks if the {@code buildMethod} is a method that creates {@code typeElement}.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.util.List;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a type has too many builder creation methods.
|
||||||
|
* This exception can be used to signal the MapStruct processor that more than one builder creation method was found.
|
||||||
|
*
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class MoreThanOneBuilderCreationMethodException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final TypeMirror type;
|
||||||
|
private final List<BuilderInfo> builderCreationMethods;
|
||||||
|
|
||||||
|
public MoreThanOneBuilderCreationMethodException(TypeMirror type, List<BuilderInfo> builderCreationMethods) {
|
||||||
|
this.type = type;
|
||||||
|
this.builderCreationMethods = builderCreationMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMirror getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BuilderInfo> getBuilderInfo() {
|
||||||
|
return builderCreationMethods;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.BeanMapping;
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.build.Process;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper(config = BuilderMapperConfig.class)
|
||||||
|
public interface BuilderConfigDefinedMapper {
|
||||||
|
|
||||||
|
BuilderConfigDefinedMapper INSTANCE = Mappers.getMapper( BuilderConfigDefinedMapper.class );
|
||||||
|
|
||||||
|
Process map(Source source);
|
||||||
|
|
||||||
|
@BeanMapping(builder = @Builder(buildMethod = "wrongCreate"))
|
||||||
|
Process wrongMap(Source source);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.BeanMapping;
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.build.Process;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper(builder = @Builder(buildMethod = "create"))
|
||||||
|
public interface BuilderDefinedMapper {
|
||||||
|
|
||||||
|
BuilderDefinedMapper INSTANCE = Mappers.getMapper( BuilderDefinedMapper.class );
|
||||||
|
|
||||||
|
Process map(Source source);
|
||||||
|
|
||||||
|
@BeanMapping(builder = @Builder(buildMethod = "wrongCreate"))
|
||||||
|
Process wrongMap(Source source);
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.MapperConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@MapperConfig(builder = @Builder(buildMethod = "create"))
|
||||||
|
public interface BuilderMapperConfig {
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface DefaultBuildMethodMapper {
|
||||||
|
|
||||||
|
DefaultBuildMethodMapper INSTANCE = Mappers.getMapper( DefaultBuildMethodMapper.class );
|
||||||
|
|
||||||
|
Task map(Source source);
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.BeanMapping;
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.build.Process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ErroneousMoreThanOneBuildMethodMapper {
|
||||||
|
|
||||||
|
Process map(Source source);
|
||||||
|
|
||||||
|
@BeanMapping(builder = @Builder(buildMethod = "missingBuild"))
|
||||||
|
Process map2(Source source);
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.build.Process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper(builder = @Builder(buildMethod = "mapperBuild"))
|
||||||
|
public interface ErroneousMoreThanOneBuildMethodWithMapperDefinedMappingMapper {
|
||||||
|
|
||||||
|
Process map(Source source);
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.build.Process;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.builder.Case;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
@IssueKey("1479")
|
||||||
|
@WithClasses({
|
||||||
|
Process.class,
|
||||||
|
Case.class,
|
||||||
|
Task.class,
|
||||||
|
Source.class
|
||||||
|
})
|
||||||
|
public class MultipleBuilderMapperTest {
|
||||||
|
|
||||||
|
@WithClasses({
|
||||||
|
ErroneousMoreThanOneBuildMethodMapper.class
|
||||||
|
})
|
||||||
|
@ExpectedCompilationOutcome(value = CompilationResult.FAILED,
|
||||||
|
diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
type = ErroneousMoreThanOneBuildMethodMapper.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 32,
|
||||||
|
messageRegExp = "No build method \"build\" found in \".*\\.multiple\\.build\\.Process\\.Builder\" " +
|
||||||
|
"for \".*\\.multiple\\.build\\.Process\"\\. " +
|
||||||
|
"Found methods: " +
|
||||||
|
"\".*wrongCreate\\(\\) ?, " +
|
||||||
|
".*create\\(\\) ?\"\\. " +
|
||||||
|
"Consider to add @Builder in order to select the correct build method."
|
||||||
|
),
|
||||||
|
@Diagnostic(
|
||||||
|
type = ErroneousMoreThanOneBuildMethodMapper.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 34,
|
||||||
|
messageRegExp = "No build method \"missingBuild\" found " +
|
||||||
|
"in \".*\\.multiple\\.build\\.Process\\.Builder\" " +
|
||||||
|
"for \".*\\.multiple\\.build\\.Process\"\\. " +
|
||||||
|
"Found methods: " +
|
||||||
|
"\".*wrongCreate\\(\\) ?, " +
|
||||||
|
".*create\\(\\) ?\"\\."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@Test
|
||||||
|
public void moreThanOneBuildMethod() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithClasses({
|
||||||
|
ErroneousMoreThanOneBuildMethodWithMapperDefinedMappingMapper.class
|
||||||
|
})
|
||||||
|
@ExpectedCompilationOutcome(value = CompilationResult.FAILED,
|
||||||
|
diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
type = ErroneousMoreThanOneBuildMethodWithMapperDefinedMappingMapper.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 31,
|
||||||
|
messageRegExp =
|
||||||
|
"No build method \"mapperBuild\" found in \".*\\.multiple\\.build\\.Process\\.Builder\" " +
|
||||||
|
"for \".*\\.multiple\\.build\\.Process\"\\. " +
|
||||||
|
"Found methods: " +
|
||||||
|
"\".*wrongCreate\\(\\) ?, " +
|
||||||
|
".*create\\(\\) ?\"\\."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@Test
|
||||||
|
public void moreThanOneBuildMethodDefinedOnMapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithClasses({
|
||||||
|
BuilderDefinedMapper.class
|
||||||
|
})
|
||||||
|
@Test
|
||||||
|
public void builderMappingDefined() {
|
||||||
|
Process map = BuilderDefinedMapper.INSTANCE.map( new Source( "map" ) );
|
||||||
|
Process wrongMap = BuilderDefinedMapper.INSTANCE.wrongMap( new Source( "wrongMap" ) );
|
||||||
|
|
||||||
|
assertThat( map.getBuildMethod() ).isEqualTo( "create" );
|
||||||
|
assertThat( wrongMap.getBuildMethod() ).isEqualTo( "wrongCreate" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithClasses({
|
||||||
|
BuilderMapperConfig.class,
|
||||||
|
BuilderConfigDefinedMapper.class
|
||||||
|
})
|
||||||
|
@Test
|
||||||
|
public void builderMappingMapperConfigDefined() {
|
||||||
|
Process map = BuilderConfigDefinedMapper.INSTANCE.map( new Source( "map" ) );
|
||||||
|
Process wrongMap = BuilderConfigDefinedMapper.INSTANCE.wrongMap( new Source( "wrongMap" ) );
|
||||||
|
|
||||||
|
assertThat( map.getBuildMethod() ).isEqualTo( "create" );
|
||||||
|
assertThat( wrongMap.getBuildMethod() ).isEqualTo( "wrongCreate" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithClasses({
|
||||||
|
TooManyBuilderCreationMethodsMapper.class
|
||||||
|
})
|
||||||
|
@ExpectedCompilationOutcome(value = CompilationResult.SUCCEEDED,
|
||||||
|
// We have 2 diagnostics, as we don't do caching of the types, so a type is processed multiple types
|
||||||
|
diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
type = Case.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.WARNING,
|
||||||
|
line = 24,
|
||||||
|
messageRegExp = "More than one builder creation method for \".*\\.multiple\\.builder.Case\"\\. " +
|
||||||
|
"Found methods: " +
|
||||||
|
"\".*wrongBuilder\\(\\) ?, " +
|
||||||
|
".*builder\\(\\) ?\"\\. " +
|
||||||
|
"Builder will not be used\\. Consider implementing a custom BuilderProvider SPI\\."
|
||||||
|
),
|
||||||
|
@Diagnostic(
|
||||||
|
type = Case.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.WARNING,
|
||||||
|
line = 24,
|
||||||
|
messageRegExp = "More than one builder creation method for \".*\\.multiple\\.builder.Case\"\\. " +
|
||||||
|
"Found methods: " +
|
||||||
|
"\".*wrongBuilder\\(\\) ?, " +
|
||||||
|
".*builder\\(\\) ?\"\\. " +
|
||||||
|
"Builder will not be used\\. Consider implementing a custom BuilderProvider SPI\\."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@Test
|
||||||
|
public void tooManyBuilderCreationMethods() {
|
||||||
|
Case caseTarget = TooManyBuilderCreationMethodsMapper.INSTANCE.map( new Source( "test" ) );
|
||||||
|
|
||||||
|
assertThat( caseTarget ).isNotNull();
|
||||||
|
assertThat( caseTarget.getName() ).isEqualTo( "test" );
|
||||||
|
assertThat( caseTarget.getBuilderCreationMethod() ).isNull();
|
||||||
|
assertThat( caseTarget.getBuildMethod() ).isEqualTo( "constructor" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithClasses( {
|
||||||
|
DefaultBuildMethodMapper.class
|
||||||
|
} )
|
||||||
|
@Test
|
||||||
|
public void defaultBuildMethod() {
|
||||||
|
Task task = DefaultBuildMethodMapper.INSTANCE.map( new Source( "test" ) );
|
||||||
|
|
||||||
|
assertThat( task ).isNotNull();
|
||||||
|
assertThat( task.getName() ).isEqualTo( "test" );
|
||||||
|
assertThat( task.getBuilderCreationMethod() ).isEqualTo( "builder" );
|
||||||
|
assertThat( task.getBuildMethod() ).isEqualTo( "build" );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Source {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public Source(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Task {
|
||||||
|
|
||||||
|
private final String builderCreationMethod;
|
||||||
|
private final String buildMethod;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Task() {
|
||||||
|
this.builderCreationMethod = null;
|
||||||
|
this.buildMethod = "constructor";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task(Builder builder, String buildMethod) {
|
||||||
|
this.builderCreationMethod = builder.builderCreationMethod;
|
||||||
|
this.buildMethod = buildMethod;
|
||||||
|
this.name = builder.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuilderCreationMethod() {
|
||||||
|
return builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuildMethod() {
|
||||||
|
return buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder( "builder" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String builderCreationMethod;
|
||||||
|
|
||||||
|
protected Builder(String builderCreationMethod) {
|
||||||
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task wrongCreate() {
|
||||||
|
return new Task( this, "wrongCreate" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task build() {
|
||||||
|
return new Task( this, "build" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ap.test.builder.multiple.builder.Case;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface TooManyBuilderCreationMethodsMapper {
|
||||||
|
|
||||||
|
TooManyBuilderCreationMethodsMapper INSTANCE = Mappers.getMapper( TooManyBuilderCreationMethodsMapper.class );
|
||||||
|
|
||||||
|
Case map(Source source);
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple.build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Process {
|
||||||
|
|
||||||
|
private final String builderCreationMethod;
|
||||||
|
private final String buildMethod;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Process() {
|
||||||
|
this.builderCreationMethod = null;
|
||||||
|
this.buildMethod = "constructor";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process(Builder builder, String buildMethod) {
|
||||||
|
this.builderCreationMethod = builder.builderCreationMethod;
|
||||||
|
this.buildMethod = buildMethod;
|
||||||
|
this.name = builder.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuilderCreationMethod() {
|
||||||
|
return builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuildMethod() {
|
||||||
|
return buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder( "builder" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String builderCreationMethod;
|
||||||
|
|
||||||
|
protected Builder(String builderCreationMethod) {
|
||||||
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process wrongCreate() {
|
||||||
|
return new Process( this, "wrongCreate" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process create() {
|
||||||
|
return new Process( this, "create" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.builder.multiple.builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Case {
|
||||||
|
|
||||||
|
private final String builderCreationMethod;
|
||||||
|
private final String buildMethod;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Case() {
|
||||||
|
this.builderCreationMethod = null;
|
||||||
|
this.buildMethod = "constructor";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Case(Builder builder, String buildMethod) {
|
||||||
|
this.builderCreationMethod = builder.builderCreationMethod;
|
||||||
|
this.buildMethod = buildMethod;
|
||||||
|
this.name = builder.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuilderCreationMethod() {
|
||||||
|
return builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuildMethod() {
|
||||||
|
return buildMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder wrongBuilder() {
|
||||||
|
return new Builder( "wrongBuilder" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder( "builder" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String builderCreationMethod;
|
||||||
|
|
||||||
|
protected Builder(String builderCreationMethod) {
|
||||||
|
this.builderCreationMethod = builderCreationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Case create() {
|
||||||
|
return new Case( this, "create" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user