mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1398 allowing @ObjectFactory
methods on context
This commit is contained in:
parent
db851701ef
commit
e67c849c17
@ -32,8 +32,9 @@ import java.lang.annotation.Target;
|
|||||||
* {@code @}{@link BeforeMapping}/{@code @}{@link AfterMapping} methods, which are called on the provided context
|
* {@code @}{@link BeforeMapping}/{@code @}{@link AfterMapping} methods, which are called on the provided context
|
||||||
* parameter value if applicable.
|
* parameter value if applicable.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Note:</strong> no {@code null} checks are performed before calling before/after mapping methods on context
|
* <strong>Note:</strong> no {@code null} checks are performed before calling before/after mapping methods or object
|
||||||
* parameters. The caller needs to make sure that no {@code null} are passed in that case.
|
* factory methods on {@code @}{@link Context} annotated parameters. The caller needs to make sure that no {@code null}
|
||||||
|
* are passed in that case.
|
||||||
* <p>
|
* <p>
|
||||||
* For generated code to call a method that is declared with {@code @Context} parameters, the declaration of the mapping
|
* For generated code to call a method that is declared with {@code @Context} parameters, the declaration of the mapping
|
||||||
* method being generated needs to contain at least those (or assignable) {@code @Context} parameters as well. MapStruct
|
* method being generated needs to contain at least those (or assignable) {@code @Context} parameters as well. MapStruct
|
||||||
@ -135,7 +136,55 @@ import java.lang.annotation.Target;
|
|||||||
* }
|
* }
|
||||||
* </code>
|
* </code>
|
||||||
* </pre>
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* <strong>Example 3:</strong> Using {@code @Context} parameters for creating an entity object by calling an
|
||||||
|
* {@code @}{@link ObjectFactory} methods:
|
||||||
*
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* // type of the context parameter
|
||||||
|
* public class ContextObjectFactory {
|
||||||
|
* @PersistenceContext(unitName = "my-unit")
|
||||||
|
* private EntityManager em;
|
||||||
|
*
|
||||||
|
* @ObjectFactory
|
||||||
|
* public Valve create( String id ) {
|
||||||
|
* Query query = em.createNamedQuery("Valve.findById");
|
||||||
|
* query.setParameter("id", id);
|
||||||
|
* Valve result = query.getSingleResult();
|
||||||
|
* if ( result != null ) {
|
||||||
|
* result = new Valve( id );
|
||||||
|
* }
|
||||||
|
* return result;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Mapper
|
||||||
|
* public interface ContextWithObjectFactoryMapper {
|
||||||
|
* Valve map(ValveDto dto, @Context ContextObjectFactory factory);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* // generates:
|
||||||
|
*
|
||||||
|
* public class ContextWithObjectFactoryMapperImpl implements ContextWithObjectFactoryMapper {
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public Valve map(ValveDto dto, ContextObjectFactory factory) {
|
||||||
|
* if ( dto == null ) {
|
||||||
|
* return null;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Valve valve = factory.create();
|
||||||
|
*
|
||||||
|
* valve.setOneWay( dto.isOneWay() );
|
||||||
|
*
|
||||||
|
* return valve;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
* @since 1.2
|
* @since 1.2
|
||||||
*/
|
*/
|
||||||
|
@ -29,14 +29,15 @@ import java.lang.annotation.Target;
|
|||||||
* By default beans are created during the mapping process with the default constructor. If a factory method with a
|
* By default beans are created during the mapping process with the default constructor. If a factory method with a
|
||||||
* return type that is assignable to the required object type is present, then the factory method is used instead.
|
* return type that is assignable to the required object type is present, then the factory method is used instead.
|
||||||
* <p>
|
* <p>
|
||||||
* Factory methods can be defined without parameters, with an {@code @}{@link TargetType} parameter, a {@code @}
|
* Factory methods can be defined without parameters, with an {@code @}{@link TargetType} parameter, a
|
||||||
* {@link Context} parameter, or with the mapping source parameter. If any of those parameters are defined, then
|
* {@code @}{@link Context} parameter, or with the mapping source parameter. If any of those parameters are defined,
|
||||||
* the mapping method that is supposed to use the factory method needs to be declared with an assignable result type,
|
* then the mapping method that is supposed to use the factory method needs to be declared with an assignable result
|
||||||
* assignable context parameter, and/or assignable source types.
|
* type, assignable context parameter, and/or assignable source types.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Note:</strong> the usage of this annotation is <em>optional</em> if no source parameters are part of the
|
* <strong>Note:</strong> the usage of this annotation is <em>optional</em> when used in the {@link Mapper#uses()}
|
||||||
* signature, i.e. it is declared without parameters or only with {@code @}{@link TargetType} and/or {@code @}
|
* if no source parameters are part of the signature, i.e. it is declared without parameters or only with
|
||||||
* {@link Context}.
|
* {@code @}{@link TargetType} and/or {@code @}{@link Context}. It is however <em>mandatory</em> when used inside
|
||||||
|
* an {@code @}{@link Context} annotated class.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Example:</strong> Using a factory method for entities to check whether the entity already exists in the
|
* <strong>Example:</strong> Using a factory method for entities to check whether the entity already exists in the
|
||||||
* EntityManager and then returns the managed instance:
|
* EntityManager and then returns the managed instance:
|
||||||
|
@ -1119,6 +1119,8 @@ public class CarMapperImpl implements CarMapper {
|
|||||||
|
|
||||||
Additional _context_ or _state_ information can be passed through generated mapping methods to custom methods with `@Context` parameters. Such parameters are passed to other mapping methods, `@ObjectFactory` methods (see <<object-factories>>) or `@BeforeMapping` / `@AfterMapping` methods (see <<customizing-mappings-with-before-and-after>>) when applicable and can thus be used in custom code.
|
Additional _context_ or _state_ information can be passed through generated mapping methods to custom methods with `@Context` parameters. Such parameters are passed to other mapping methods, `@ObjectFactory` methods (see <<object-factories>>) or `@BeforeMapping` / `@AfterMapping` methods (see <<customizing-mappings-with-before-and-after>>) when applicable and can thus be used in custom code.
|
||||||
|
|
||||||
|
`@Context` parameters are searched for `@ObjectFactory` methods, which are called on the provided context parameter value if applicable.
|
||||||
|
|
||||||
`@Context` parameters are also searched for `@BeforeMapping` / `@AfterMapping` methods, which are called on the provided context parameter value if applicable.
|
`@Context` parameters are also searched for `@BeforeMapping` / `@AfterMapping` methods, which are called on the provided context parameter value if applicable.
|
||||||
|
|
||||||
*Note:* no `null` checks are performed before calling before/after mapping methods on context parameters. The caller needs to make sure that `null` is not passed in that case.
|
*Note:* no `null` checks are performed before calling before/after mapping methods on context parameters. The caller needs to make sure that `null` is not passed in that case.
|
||||||
|
@ -190,10 +190,11 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
|
|
||||||
MethodReference factoryMethod = null;
|
MethodReference factoryMethod = null;
|
||||||
if ( !method.isUpdateMethod() ) {
|
if ( !method.isUpdateMethod() ) {
|
||||||
factoryMethod = ctx.getMappingResolver().getFactoryMethod(
|
factoryMethod = ObjectFactoryMethodResolver.getFactoryMethod(
|
||||||
method,
|
method,
|
||||||
method.getResultType(),
|
method.getResultType(),
|
||||||
selectionParameters
|
selectionParameters,
|
||||||
|
ctx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,14 +247,14 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
|
|
||||||
sortPropertyMappingsByDependencies();
|
sortPropertyMappingsByDependencies();
|
||||||
|
|
||||||
List<LifecycleCallbackMethodReference> beforeMappingMethods = LifecycleCallbackFactory.beforeMappingMethods(
|
List<LifecycleCallbackMethodReference> beforeMappingMethods = LifecycleMethodResolver.beforeMappingMethods(
|
||||||
method,
|
method,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
ctx,
|
ctx,
|
||||||
existingVariableNames
|
existingVariableNames
|
||||||
);
|
);
|
||||||
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
||||||
LifecycleCallbackFactory.afterMappingMethods( method, selectionParameters, ctx, existingVariableNames );
|
LifecycleMethodResolver.afterMappingMethods( method, selectionParameters, ctx, existingVariableNames );
|
||||||
|
|
||||||
if (factoryMethod != null && method instanceof ForgedMethod ) {
|
if (factoryMethod != null && method instanceof ForgedMethod ) {
|
||||||
( (ForgedMethod) method ).addThrownTypes( factoryMethod.getThrownTypes() );
|
( (ForgedMethod) method ).addThrownTypes( factoryMethod.getThrownTypes() );
|
||||||
|
@ -141,8 +141,8 @@ public class CollectionAssignmentBuilder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assignment factoryMethod = ctx.getMappingResolver()
|
Assignment factoryMethod = ObjectFactoryMethodResolver
|
||||||
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( sourceRHS ) );
|
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( sourceRHS ), ctx );
|
||||||
result = new UpdateWrapper(
|
result = new UpdateWrapper(
|
||||||
result,
|
result,
|
||||||
method.getThrownTypes(),
|
method.getThrownTypes(),
|
||||||
|
@ -138,19 +138,19 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
|
|||||||
|
|
||||||
MethodReference factoryMethod = null;
|
MethodReference factoryMethod = null;
|
||||||
if ( !method.isUpdateMethod() ) {
|
if ( !method.isUpdateMethod() ) {
|
||||||
factoryMethod = ctx.getMappingResolver().getFactoryMethod( method, method.getResultType(), null );
|
factoryMethod = ObjectFactoryMethodResolver.getFactoryMethod( method, method.getResultType(), null, ctx );
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
||||||
existingVariables.add( loopVariableName );
|
existingVariables.add( loopVariableName );
|
||||||
|
|
||||||
List<LifecycleCallbackMethodReference> beforeMappingMethods = LifecycleCallbackFactory.beforeMappingMethods(
|
List<LifecycleCallbackMethodReference> beforeMappingMethods = LifecycleMethodResolver.beforeMappingMethods(
|
||||||
method,
|
method,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
ctx,
|
ctx,
|
||||||
existingVariables
|
existingVariables
|
||||||
);
|
);
|
||||||
List<LifecycleCallbackMethodReference> afterMappingMethods = LifecycleCallbackFactory.afterMappingMethods(
|
List<LifecycleCallbackMethodReference> afterMappingMethods = LifecycleMethodResolver.afterMappingMethods(
|
||||||
method,
|
method,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -104,9 +104,9 @@ public class EnumMappingMethod extends MappingMethod {
|
|||||||
|
|
||||||
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
||||||
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
||||||
LifecycleCallbackFactory.beforeMappingMethods( method, selectionParameters, ctx, existingVariables );
|
LifecycleMethodResolver.beforeMappingMethods( method, selectionParameters, ctx, existingVariables );
|
||||||
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
||||||
LifecycleCallbackFactory.afterMappingMethods( method, selectionParameters, ctx, existingVariables );
|
LifecycleMethodResolver.afterMappingMethods( method, selectionParameters, ctx, existingVariables );
|
||||||
|
|
||||||
return new EnumMappingMethod( method, enumMappings, beforeMappingMethods, afterMappingMethods );
|
return new EnumMappingMethod( method, enumMappings, beforeMappingMethods, afterMappingMethods );
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,9 @@ import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
|
|||||||
*
|
*
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
*/
|
*/
|
||||||
public final class LifecycleCallbackFactory {
|
public final class LifecycleMethodResolver {
|
||||||
|
|
||||||
private LifecycleCallbackFactory() {
|
private LifecycleMethodResolver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,8 +54,7 @@ public final class LifecycleCallbackFactory {
|
|||||||
SelectionParameters selectionParameters,
|
SelectionParameters selectionParameters,
|
||||||
MappingBuilderContext ctx,
|
MappingBuilderContext ctx,
|
||||||
Set<String> existingVariableNames) {
|
Set<String> existingVariableNames) {
|
||||||
return collectLifecycleCallbackMethods(
|
return collectLifecycleCallbackMethods( method,
|
||||||
method,
|
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
filterBeforeMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
|
filterBeforeMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
|
||||||
ctx,
|
ctx,
|
||||||
@ -73,8 +72,7 @@ public final class LifecycleCallbackFactory {
|
|||||||
SelectionParameters selectionParameters,
|
SelectionParameters selectionParameters,
|
||||||
MappingBuilderContext ctx,
|
MappingBuilderContext ctx,
|
||||||
Set<String> existingVariableNames) {
|
Set<String> existingVariableNames) {
|
||||||
return collectLifecycleCallbackMethods(
|
return collectLifecycleCallbackMethods( method,
|
||||||
method,
|
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
|
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
|
||||||
ctx,
|
ctx,
|
||||||
@ -93,7 +91,9 @@ public final class LifecycleCallbackFactory {
|
|||||||
List<SourceMethod> availableMethods =
|
List<SourceMethod> availableMethods =
|
||||||
new ArrayList<SourceMethod>( methodsProvidedByParams.size() + sourceModelMethods.size() );
|
new ArrayList<SourceMethod>( methodsProvidedByParams.size() + sourceModelMethods.size() );
|
||||||
|
|
||||||
availableMethods.addAll( methodsProvidedByParams );
|
for ( SourceMethod methodProvidedByParams : methodsProvidedByParams ) {
|
||||||
|
availableMethods.add( methodProvidedByParams );
|
||||||
|
}
|
||||||
availableMethods.addAll( sourceModelMethods );
|
availableMethods.addAll( sourceModelMethods );
|
||||||
|
|
||||||
return availableMethods;
|
return availableMethods;
|
||||||
@ -144,7 +144,7 @@ public final class LifecycleCallbackFactory {
|
|||||||
existingVariableNames ) );
|
existingVariableNames ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MapperReference mapperReference = findMapperReference(
|
MapperReference mapperReference = MapperReference.findMapperReference(
|
||||||
ctx.getMapperReferences(),
|
ctx.getMapperReferences(),
|
||||||
candidate.getMethod() );
|
candidate.getMethod() );
|
||||||
|
|
||||||
@ -158,17 +158,6 @@ public final class LifecycleCallbackFactory {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MapperReference findMapperReference(List<MapperReference> mapperReferences, SourceMethod method) {
|
|
||||||
for ( MapperReference ref : mapperReferences ) {
|
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
|
||||||
ref.setUsed( ref.isUsed() || !method.isStatic() );
|
|
||||||
ref.setTypeRequiresImport( true );
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<SourceMethod> filterBeforeMappingMethods(List<SourceMethod> methods) {
|
private static List<SourceMethod> filterBeforeMappingMethods(List<SourceMethod> methods) {
|
||||||
List<SourceMethod> result = new ArrayList<SourceMethod>();
|
List<SourceMethod> result = new ArrayList<SourceMethod>();
|
||||||
for ( SourceMethod method : methods ) {
|
for ( SourceMethod method : methods ) {
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -36,8 +38,6 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
|||||||
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one {@code Map} type to another. Keys and
|
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one {@code Map} type to another. Keys and
|
||||||
* values are mapped either by a {@link TypeConversion} or another mapping method if required.
|
* values are mapped either by a {@link TypeConversion} or another mapping method if required.
|
||||||
@ -191,7 +191,8 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
|
|
||||||
MethodReference factoryMethod = null;
|
MethodReference factoryMethod = null;
|
||||||
if ( !method.isUpdateMethod() ) {
|
if ( !method.isUpdateMethod() ) {
|
||||||
factoryMethod = ctx.getMappingResolver().getFactoryMethod( method, method.getResultType(), null );
|
factoryMethod = ObjectFactoryMethodResolver
|
||||||
|
.getFactoryMethod( method, method.getResultType(), null, ctx );
|
||||||
}
|
}
|
||||||
|
|
||||||
keyAssignment = new LocalVarWrapper( keyAssignment, method.getThrownTypes(), keyTargetType, false );
|
keyAssignment = new LocalVarWrapper( keyAssignment, method.getThrownTypes(), keyTargetType, false );
|
||||||
@ -199,9 +200,9 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
|
|
||||||
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
||||||
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
||||||
LifecycleCallbackFactory.beforeMappingMethods( method, null, ctx, existingVariables );
|
LifecycleMethodResolver.beforeMappingMethods( method, null, ctx, existingVariables );
|
||||||
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
||||||
LifecycleCallbackFactory.afterMappingMethods( method, null, ctx, existingVariables );
|
LifecycleMethodResolver.afterMappingMethods( method, null, ctx, existingVariables );
|
||||||
|
|
||||||
return new MapMappingMethod(
|
return new MapMappingMethod(
|
||||||
method,
|
method,
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
|
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to another mapper class, which itself may be generated or hand-written.
|
* A reference to another mapper class, which itself may be generated or hand-written.
|
||||||
@ -34,4 +36,15 @@ public abstract class MapperReference extends Field {
|
|||||||
public MapperReference(Type type, String variableName, boolean isUsed) {
|
public MapperReference(Type type, String variableName, boolean isUsed) {
|
||||||
super( type, variableName, isUsed );
|
super( type, variableName, isUsed );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MapperReference findMapperReference(List<MapperReference> mapperReferences, SourceMethod method) {
|
||||||
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
|
ref.setUsed( ref.isUsed() || !method.isStatic() );
|
||||||
|
ref.setTypeRequiresImport( true );
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,18 +107,6 @@ public class MappingBuilderContext {
|
|||||||
SelectionParameters selectionParameters, SourceRHS sourceRHS,
|
SelectionParameters selectionParameters, SourceRHS sourceRHS,
|
||||||
boolean preferUpdateMethods);
|
boolean preferUpdateMethods);
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a no arg factory method
|
|
||||||
*
|
|
||||||
* @param mappingMethod target mapping method
|
|
||||||
* @param target return type to match
|
|
||||||
* @param selectionParameters parameters used in the selection process
|
|
||||||
*
|
|
||||||
* @return a method reference to the factory method, or null if no suitable, or ambiguous method found
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
MethodReference getFactoryMethod(Method mappingMethod, Type target, SelectionParameters selectionParameters);
|
|
||||||
|
|
||||||
Set<VirtualMappingMethod> getUsedVirtualMappings();
|
Set<VirtualMappingMethod> getUsedVirtualMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* 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 static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
|
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||||
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
|
import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods;
|
||||||
|
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||||
|
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
||||||
|
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.Message;
|
||||||
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class ObjectFactoryMethodResolver {
|
||||||
|
|
||||||
|
private ObjectFactoryMethodResolver() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a no arg factory method
|
||||||
|
*
|
||||||
|
* @param method target mapping method
|
||||||
|
* @param targetType return type to match
|
||||||
|
* @param selectionParameters parameters used in the selection process
|
||||||
|
* @param ctx
|
||||||
|
*
|
||||||
|
* @return a method reference to the factory method, or null if no suitable, or ambiguous method found
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static MethodReference getFactoryMethod( Method method,
|
||||||
|
Type targetType,
|
||||||
|
SelectionParameters selectionParameters,
|
||||||
|
MappingBuilderContext ctx) {
|
||||||
|
|
||||||
|
MethodSelectors selectors =
|
||||||
|
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory() );
|
||||||
|
|
||||||
|
List<SelectedMethod<SourceMethod>> matchingFactoryMethods =
|
||||||
|
selectors.getMatchingMethods(
|
||||||
|
method,
|
||||||
|
getAllAvailableMethods( method, ctx.getSourceModel() ),
|
||||||
|
java.util.Collections.<Type> emptyList(),
|
||||||
|
targetType.getEffectiveType(),
|
||||||
|
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
||||||
|
|
||||||
|
if (matchingFactoryMethods.isEmpty()) {
|
||||||
|
return findBuilderFactoryMethod( targetType );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( matchingFactoryMethods.size() > 1 ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
method.getExecutable(),
|
||||||
|
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
|
||||||
|
targetType.getEffectiveType(),
|
||||||
|
Strings.join( matchingFactoryMethods, ", " ) );
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedMethod<SourceMethod> matchingFactoryMethod = first( matchingFactoryMethods );
|
||||||
|
|
||||||
|
Parameter providingParameter =
|
||||||
|
method.getContextProvidedMethods().getParameterForProvidedMethod( matchingFactoryMethod.getMethod() );
|
||||||
|
|
||||||
|
if ( providingParameter != null ) {
|
||||||
|
return MethodReference.forParameterProvidedMethod(
|
||||||
|
matchingFactoryMethod.getMethod(),
|
||||||
|
providingParameter,
|
||||||
|
matchingFactoryMethod.getParameterBindings() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MapperReference ref = MapperReference.findMapperReference(
|
||||||
|
ctx.getMapperReferences(),
|
||||||
|
matchingFactoryMethod.getMethod() );
|
||||||
|
|
||||||
|
return MethodReference.forMapperReference(
|
||||||
|
matchingFactoryMethod.getMethod(),
|
||||||
|
ref,
|
||||||
|
matchingFactoryMethod.getParameterBindings() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodReference findBuilderFactoryMethod(Type targetType) {
|
||||||
|
BuilderType builder = targetType.getBuilderType();
|
||||||
|
if ( builder == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getOwningType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<SourceMethod> getAllAvailableMethods(Method method, List<SourceMethod> sourceModelMethods) {
|
||||||
|
ParameterProvidedMethods contextProvidedMethods = method.getContextProvidedMethods();
|
||||||
|
if ( contextProvidedMethods.isEmpty() ) {
|
||||||
|
return sourceModelMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SourceMethod> methodsProvidedByParams = contextProvidedMethods
|
||||||
|
.getAllProvidedMethodsInParameterOrder( method.getContextParameters() );
|
||||||
|
|
||||||
|
List<SourceMethod> availableMethods =
|
||||||
|
new ArrayList<SourceMethod>( methodsProvidedByParams.size() + sourceModelMethods.size() );
|
||||||
|
|
||||||
|
for ( SourceMethod methodProvidedByParams : methodsProvidedByParams ) {
|
||||||
|
// add only methods from context that do have the @ObjectFactory annotation
|
||||||
|
if ( methodProvidedByParams.hasObjectFactoryAnnotation() ) {
|
||||||
|
availableMethods.add( methodProvidedByParams );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
availableMethods.addAll( sourceModelMethods );
|
||||||
|
|
||||||
|
return availableMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,13 +18,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.model.common.Assignment.AssignmentType.DIRECT;
|
||||||
|
import static org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism.ALWAYS;
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.last;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
|
||||||
|
|
||||||
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
|
||||||
@ -54,16 +59,11 @@ import org.mapstruct.ap.internal.util.AccessorNamingUtils;
|
|||||||
import org.mapstruct.ap.internal.util.Executables;
|
import org.mapstruct.ap.internal.util.Executables;
|
||||||
import org.mapstruct.ap.internal.util.MapperConfiguration;
|
import org.mapstruct.ap.internal.util.MapperConfiguration;
|
||||||
import org.mapstruct.ap.internal.util.Message;
|
import org.mapstruct.ap.internal.util.Message;
|
||||||
|
import org.mapstruct.ap.internal.util.NativeTypes;
|
||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
import org.mapstruct.ap.internal.util.ValueProvider;
|
import org.mapstruct.ap.internal.util.ValueProvider;
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.model.common.Assignment.AssignmentType.DIRECT;
|
|
||||||
import static org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism.ALWAYS;
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.last;
|
|
||||||
import org.mapstruct.ap.internal.util.NativeTypes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the mapping between a source and target property, e.g. from {@code String Source#foo} to
|
* Represents the mapping between a source and target property, e.g. from {@code String Source#foo} to
|
||||||
* {@code int Target#bar}. Name and type of source and target property can differ. If they have different types, the
|
* {@code int Target#bar}. Name and type of source and target property can differ. If they have different types, the
|
||||||
@ -433,8 +433,8 @@ public class PropertyMapping extends ModelElement {
|
|||||||
boolean mapNullToDefault = method.getMapperConfiguration().
|
boolean mapNullToDefault = method.getMapperConfiguration().
|
||||||
getNullValueMappingStrategy() == NullValueMappingStrategyPrism.RETURN_DEFAULT;
|
getNullValueMappingStrategy() == NullValueMappingStrategyPrism.RETURN_DEFAULT;
|
||||||
|
|
||||||
Assignment factory = ctx.getMappingResolver()
|
Assignment factory = ObjectFactoryMethodResolver
|
||||||
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( rightHandSide ) );
|
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( rightHandSide ), ctx );
|
||||||
return new UpdateWrapper( rhs, method.getThrownTypes(), factory, isFieldAssignment(), targetType,
|
return new UpdateWrapper( rhs, method.getThrownTypes(), factory, isFieldAssignment(), targetType,
|
||||||
!rhs.isSourceReferenceParameter(), mapNullToDefault );
|
!rhs.isSourceReferenceParameter(), mapNullToDefault );
|
||||||
}
|
}
|
||||||
@ -816,7 +816,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
getNullValueMappingStrategy() == NullValueMappingStrategyPrism.RETURN_DEFAULT;
|
getNullValueMappingStrategy() == NullValueMappingStrategyPrism.RETURN_DEFAULT;
|
||||||
|
|
||||||
Assignment factoryMethod =
|
Assignment factoryMethod =
|
||||||
ctx.getMappingResolver().getFactoryMethod( method, targetType, null );
|
ObjectFactoryMethodResolver.getFactoryMethod( method, targetType, null, ctx );
|
||||||
|
|
||||||
assignment = new UpdateWrapper( assignment, method.getThrownTypes(), factoryMethod,
|
assignment = new UpdateWrapper( assignment, method.getThrownTypes(), factoryMethod,
|
||||||
isFieldAssignment(), targetType, false, mapNullToDefault );
|
isFieldAssignment(), targetType, false, mapNullToDefault );
|
||||||
|
@ -122,9 +122,9 @@ public class ValueMappingMethod extends MappingMethod {
|
|||||||
SelectionParameters selectionParameters = getSelectionParameters( method, ctx.getTypeUtils() );
|
SelectionParameters selectionParameters = getSelectionParameters( method, ctx.getTypeUtils() );
|
||||||
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
Set<String> existingVariables = new HashSet<String>( method.getParameterNames() );
|
||||||
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
List<LifecycleCallbackMethodReference> beforeMappingMethods =
|
||||||
LifecycleCallbackFactory.beforeMappingMethods( method, selectionParameters, ctx, existingVariables );
|
LifecycleMethodResolver.beforeMappingMethods( method, selectionParameters, ctx, existingVariables );
|
||||||
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
List<LifecycleCallbackMethodReference> afterMappingMethods =
|
||||||
LifecycleCallbackFactory.afterMappingMethods( method, selectionParameters, ctx, existingVariables );
|
LifecycleMethodResolver.afterMappingMethods( method, selectionParameters, ctx, existingVariables );
|
||||||
|
|
||||||
// finally return a mapping
|
// finally return a mapping
|
||||||
return new ValueMappingMethod( method, mappingEntries, nullTarget, defaultTarget,
|
return new ValueMappingMethod( method, mappingEntries, nullTarget, defaultTarget,
|
||||||
|
@ -79,12 +79,12 @@ public class SourceMethod implements Method {
|
|||||||
private List<SourceMethod> applicablePrototypeMethods;
|
private List<SourceMethod> applicablePrototypeMethods;
|
||||||
private List<SourceMethod> applicableReversePrototypeMethods;
|
private List<SourceMethod> applicableReversePrototypeMethods;
|
||||||
|
|
||||||
private Boolean isBeanMapping;
|
|
||||||
private Boolean isEnumMapping;
|
private Boolean isEnumMapping;
|
||||||
private Boolean isValueMapping;
|
private Boolean isValueMapping;
|
||||||
private Boolean isIterableMapping;
|
private Boolean isIterableMapping;
|
||||||
private Boolean isMapMapping;
|
private Boolean isMapMapping;
|
||||||
private Boolean isStreamMapping;
|
private Boolean isStreamMapping;
|
||||||
|
private final boolean hasObjectFactoryAnnotation;
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
@ -231,7 +231,8 @@ public class SourceMethod implements Method {
|
|||||||
|
|
||||||
this.mappingTargetParameter = Parameter.getMappingTargetParameter( parameters );
|
this.mappingTargetParameter = Parameter.getMappingTargetParameter( parameters );
|
||||||
this.targetTypeParameter = Parameter.getTargetTypeParameter( parameters );
|
this.targetTypeParameter = Parameter.getTargetTypeParameter( parameters );
|
||||||
this.isObjectFactory = determineIfIsObjectFactory( executable );
|
this.hasObjectFactoryAnnotation = ObjectFactoryPrism.getInstanceOn( executable ) != null;
|
||||||
|
this.isObjectFactory = determineIfIsObjectFactory();
|
||||||
|
|
||||||
this.typeUtils = builder.typeUtils;
|
this.typeUtils = builder.typeUtils;
|
||||||
this.typeFactory = builder.typeFactory;
|
this.typeFactory = builder.typeFactory;
|
||||||
@ -240,13 +241,12 @@ public class SourceMethod implements Method {
|
|||||||
this.mapperToImplement = builder.definingType;
|
this.mapperToImplement = builder.definingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean determineIfIsObjectFactory(ExecutableElement executable) {
|
private boolean determineIfIsObjectFactory() {
|
||||||
boolean hasFactoryAnnotation = ObjectFactoryPrism.getInstanceOn( executable ) != null;
|
|
||||||
boolean hasNoSourceParameters = getSourceParameters().isEmpty();
|
boolean hasNoSourceParameters = getSourceParameters().isEmpty();
|
||||||
boolean hasNoMappingTargetParam = getMappingTargetParameter() == null;
|
boolean hasNoMappingTargetParam = getMappingTargetParameter() == null;
|
||||||
return !isLifecycleCallbackMethod() && !returnType.isVoid()
|
return !isLifecycleCallbackMethod() && !returnType.isVoid()
|
||||||
&& hasNoMappingTargetParam
|
&& hasNoMappingTargetParam
|
||||||
&& ( hasFactoryAnnotation || hasNoSourceParameters );
|
&& ( hasObjectFactoryAnnotation || hasNoSourceParameters );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -606,4 +606,8 @@ public class SourceMethod implements Method {
|
|||||||
public boolean isUpdateMethod() {
|
public boolean isUpdateMethod() {
|
||||||
return getMappingTargetParameter() != null;
|
return getMappingTargetParameter() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasObjectFactoryAnnotation() {
|
||||||
|
return hasObjectFactoryAnnotation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParameterProvidedMethods contextProvidedMethods =
|
ParameterProvidedMethods contextProvidedMethods =
|
||||||
retrieveLifecycleMethodsFromContext( contextParameters, mapperToImplement, mapperConfig );
|
retrieveContextProvidedMethods( contextParameters, mapperToImplement, mapperConfig );
|
||||||
|
|
||||||
return new SourceMethod.Builder()
|
return new SourceMethod.Builder()
|
||||||
.setExecutable( method )
|
.setExecutable( method )
|
||||||
@ -275,7 +275,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterProvidedMethods retrieveLifecycleMethodsFromContext(
|
private ParameterProvidedMethods retrieveContextProvidedMethods(
|
||||||
List<Parameter> contextParameters, TypeElement mapperToImplement, MapperConfiguration mapperConfig) {
|
List<Parameter> contextParameters, TypeElement mapperToImplement, MapperConfiguration mapperConfig) {
|
||||||
|
|
||||||
ParameterProvidedMethods.Builder builder = ParameterProvidedMethods.builder();
|
ParameterProvidedMethods.Builder builder = ParameterProvidedMethods.builder();
|
||||||
@ -289,14 +289,14 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
mapperConfig,
|
mapperConfig,
|
||||||
Collections.<SourceMethod> emptyList() );
|
Collections.<SourceMethod> emptyList() );
|
||||||
|
|
||||||
List<SourceMethod> lifecycleMethods = new ArrayList<SourceMethod>( contextParamMethods.size() );
|
List<SourceMethod> contextProvidedMethods = new ArrayList<SourceMethod>( contextParamMethods.size() );
|
||||||
for ( SourceMethod sourceMethod : contextParamMethods ) {
|
for ( SourceMethod sourceMethod : contextParamMethods ) {
|
||||||
if ( sourceMethod.isLifecycleCallbackMethod() ) {
|
if ( sourceMethod.isLifecycleCallbackMethod() || sourceMethod.isObjectFactory() ) {
|
||||||
lifecycleMethods.add( sourceMethod );
|
contextProvidedMethods.add( sourceMethod );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.addMethodsForParameter( contextParam, lifecycleMethods );
|
builder.addMethodsForParameter( contextParam, contextProvidedMethods );
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
|
@ -26,7 +26,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.lang.model.element.ElementKind;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
@ -45,7 +44,6 @@ import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
|||||||
import org.mapstruct.ap.internal.model.MethodReference;
|
import org.mapstruct.ap.internal.model.MethodReference;
|
||||||
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
||||||
import org.mapstruct.ap.internal.model.common.Assignment;
|
import org.mapstruct.ap.internal.model.common.Assignment;
|
||||||
import org.mapstruct.ap.internal.model.common.BuilderType;
|
|
||||||
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
import org.mapstruct.ap.internal.model.common.FormattingParameters;
|
||||||
@ -129,65 +127,6 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
return usedVirtualMappings;
|
return usedVirtualMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MethodReference getFactoryMethod(final Method mappingMethod, Type targetType,
|
|
||||||
SelectionParameters selectionParameters) {
|
|
||||||
|
|
||||||
List<SelectedMethod<Method>> matchingFactoryMethods =
|
|
||||||
methodSelectors.getMatchingMethods(
|
|
||||||
mappingMethod,
|
|
||||||
sourceModel,
|
|
||||||
java.util.Collections.<Type> emptyList(),
|
|
||||||
targetType.getEffectiveType(),
|
|
||||||
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
|
||||||
|
|
||||||
if (matchingFactoryMethods.isEmpty()) {
|
|
||||||
return findBuilderFactoryMethod( targetType );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( matchingFactoryMethods.size() > 1 ) {
|
|
||||||
messager.printMessage(
|
|
||||||
mappingMethod.getExecutable(),
|
|
||||||
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
|
|
||||||
targetType.getEffectiveType(),
|
|
||||||
Strings.join( matchingFactoryMethods, ", " ) );
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectedMethod<Method> matchingFactoryMethod = first( matchingFactoryMethods );
|
|
||||||
|
|
||||||
MapperReference ref = findMapperReference( matchingFactoryMethod.getMethod() );
|
|
||||||
|
|
||||||
return MethodReference.forMapperReference(
|
|
||||||
matchingFactoryMethod.getMethod(),
|
|
||||||
ref,
|
|
||||||
matchingFactoryMethod.getParameterBindings() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodReference findBuilderFactoryMethod(Type targetType) {
|
|
||||||
BuilderType builder = targetType.getBuilderType();
|
|
||||||
if ( builder == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.getOwningType()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MapperReference findMapperReference(Method method) {
|
private MapperReference findMapperReference(Method method) {
|
||||||
for ( MapperReference ref : mapperReferences ) {
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
|
@ -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.context.objectfactory;
|
||||||
|
|
||||||
|
import org.mapstruct.ObjectFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
public class ContextObjectFactory {
|
||||||
|
|
||||||
|
@ObjectFactory
|
||||||
|
public Valve create() {
|
||||||
|
return new Valve("123id");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.context.objectfactory;
|
||||||
|
|
||||||
|
import org.mapstruct.Context;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ContextWithObjectFactoryMapper {
|
||||||
|
|
||||||
|
ContextWithObjectFactoryMapper INSTANCE = Mappers.getMapper( ContextWithObjectFactoryMapper.class );
|
||||||
|
|
||||||
|
Valve map(ValveDto dto, @Context ContextObjectFactory factory);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* 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.context.objectfactory;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
@IssueKey( "1398" )
|
||||||
|
@WithClasses({
|
||||||
|
Valve.class,
|
||||||
|
ValveDto.class,
|
||||||
|
ContextObjectFactory.class,
|
||||||
|
ContextWithObjectFactoryMapper.class})
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
public class ContextWithObjectFactoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFactoryCalled( ) {
|
||||||
|
ValveDto dto = new ValveDto();
|
||||||
|
dto.setOneWay( true );
|
||||||
|
|
||||||
|
Valve result = ContextWithObjectFactoryMapper.INSTANCE.map( dto, new ContextObjectFactory() );
|
||||||
|
|
||||||
|
assertThat( result ).isNotNull();
|
||||||
|
assertThat( result.isOneWay() ).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.context.objectfactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class Valve {
|
||||||
|
|
||||||
|
private boolean oneWay;
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public Valve(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOneWay() {
|
||||||
|
return oneWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOneWay(boolean oneWay) {
|
||||||
|
this.oneWay = oneWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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.context.objectfactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class ValveDto {
|
||||||
|
|
||||||
|
private boolean oneWay;
|
||||||
|
|
||||||
|
public boolean isOneWay() {
|
||||||
|
return oneWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOneWay(boolean oneWay) {
|
||||||
|
this.oneWay = oneWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user