#120 Method and BuiltInMethod implement a common interface that can be used for matching.

This commit is contained in:
sjaakd 2014-02-18 21:00:45 +01:00 committed by Gunnar Morling
parent 08b6008ed1
commit 2471edcf69
20 changed files with 517 additions and 516 deletions

View File

@ -18,103 +18,27 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import java.util.ArrayList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.tools.Diagnostic;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
import org.mapstruct.ap.util.Strings;
/**
* Registry for all build in methods.
*
* @author Sjaak Derksen
*/
public class BuiltInMappingMethods {
public class BuiltInMappingMethods extends HashSet<BuiltInMethod> {
private final Set<BuiltInMappingMethod> builtInMethods = new HashSet<BuiltInMappingMethod>();
private final Messager messager;
public BuiltInMappingMethods( TypeFactory typeFactory ) {
public BuiltInMappingMethods( Messager messager, TypeFactory typeFactory ) {
this.messager = messager;
builtInMethods.add( new JaxbElemToValue( typeFactory ) );
builtInMethods.add( new ListOfJaxbElemToListOfValue( typeFactory ) );
builtInMethods.add( new DateToXmlGregorianCalendar( typeFactory ) );
builtInMethods.add( new XmlGregorianCalendarToDate( typeFactory ) );
builtInMethods.add( new StringToXmlGregorianCalendar( typeFactory ) );
builtInMethods.add( new XmlGregorianCalendarToString( typeFactory ) );
builtInMethods.add( new CalendarToXmlGregorianCalendar( typeFactory ) );
builtInMethods.add( new XmlGregorianCalendarToCalendar( typeFactory ) );
}
/**
* The method looks for a match on equal source type and best matching target type (minimum distance) TODO:
* investigate whether also the best matching source type should be investigating iso equal.
*
* @param sourceType
* @param targetType
* @return
*/
public BuiltInMappingMethod getConversion( Type sourceType, Type targetType ) {
List<BuiltInMappingMethod> candidates = new ArrayList<BuiltInMappingMethod>();
int bestMatchingTargetTypeDistance = Integer.MAX_VALUE;
for ( BuiltInMappingMethod entry : builtInMethods ) {
if ( targetType.erasure().isAssignableTo( entry.target() )
&& sourceType.erasure().isAssignableTo( entry.source() ) ) {
if ( entry.doGenericsMatch( sourceType, targetType ) ) {
int sourceTypeDistance = targetType.distanceTo( entry.target() );
bestMatchingTargetTypeDistance
= addToCandidateListIfMinimal(
candidates,
bestMatchingTargetTypeDistance,
entry,
sourceTypeDistance );
}
}
}
if ( candidates.isEmpty() ) {
return null;
}
if ( candidates.size() > 1 ) {
// print a warning if we find more than one method with minimum source type distance
List<String> builtInMethodNames = new ArrayList<String>();
for ( BuiltInMappingMethod candidate : candidates ) {
builtInMethodNames.add( candidate.getName() );
}
messager.printMessage(
Diagnostic.Kind.ERROR,
String.format(
"MapStruct error. Conflicting build-in methods %s for sourceType: %s, targetTypes %s.",
Strings.join( builtInMethodNames, ", " ),
sourceType,
targetType )
);
}
return candidates.get( 0 );
}
private int addToCandidateListIfMinimal( List<BuiltInMappingMethod> candidatesWithBestMathingType,
int bestMatchingTypeDistance, BuiltInMappingMethod builtInMethod, int currentTypeDistance ) {
if ( currentTypeDistance == bestMatchingTypeDistance ) {
candidatesWithBestMathingType.add( builtInMethod );
}
else if ( currentTypeDistance < bestMatchingTypeDistance ) {
bestMatchingTypeDistance = currentTypeDistance;
candidatesWithBestMathingType.clear();
candidatesWithBestMathingType.add( builtInMethod );
}
return bestMatchingTypeDistance;
add( new JaxbElemToValue( typeFactory ) );
add( new ListOfJaxbElemToListOfValue( typeFactory ) );
add( new DateToXmlGregorianCalendar( typeFactory ) );
add( new XmlGregorianCalendarToDate( typeFactory ) );
add( new StringToXmlGregorianCalendar( typeFactory ) );
add( new XmlGregorianCalendarToString( typeFactory ) );
add( new CalendarToXmlGregorianCalendar( typeFactory ) );
add( new XmlGregorianCalendarToCalendar( typeFactory ) );
}
}

View File

@ -18,15 +18,13 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -36,25 +34,17 @@ import static org.mapstruct.ap.util.Collections.asSet;
*
* @author Sjaak Derksen
*/
public class CalendarToXmlGregorianCalendar extends BuiltInMappingMethod {
public class CalendarToXmlGregorianCalendar extends BuiltInMethod {
private static final Class SOURCE = Calendar.class;
private static final Class TARGET = XMLGregorianCalendar.class;
private final Parameter parameter;
private final Type returnType;
private final TypeFactory typeFactory;
public CalendarToXmlGregorianCalendar( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "cal", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
this.parameter = typeFactory.createParameter( "cal ", Calendar.class );
this.returnType = typeFactory.getType( XMLGregorianCalendar.class );
}
@Override
@ -65,12 +55,12 @@ public class CalendarToXmlGregorianCalendar extends BuiltInMappingMethod {
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Parameter getParameter() {
return parameter;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -18,15 +18,13 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -36,25 +34,17 @@ import static org.mapstruct.ap.util.Collections.asSet;
*
* @author Sjaak Derksen
*/
public class DateToXmlGregorianCalendar extends BuiltInMappingMethod {
public class DateToXmlGregorianCalendar extends BuiltInMethod {
private static final Class SOURCE = Date.class;
private static final Class TARGET = XMLGregorianCalendar.class;
private final Parameter parameter;
private final Type returnType;
private final TypeFactory typeFactory;
public DateToXmlGregorianCalendar( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "date", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
this.parameter = typeFactory.createParameter( "date", Date.class );
this.returnType = typeFactory.getType( XMLGregorianCalendar.class );
}
@Override
@ -65,12 +55,12 @@ public class DateToXmlGregorianCalendar extends BuiltInMappingMethod {
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Parameter getParameter() {
return parameter;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -18,10 +18,8 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import javax.xml.bind.JAXBElement;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -30,29 +28,18 @@ import org.mapstruct.ap.model.common.TypeFactory;
*
* @author Sjaak Derksen
*/
public class JaxbElemToValue extends BuiltInMappingMethod {
public class JaxbElemToValue extends BuiltInMethod {
private static final Class SOURCE = JAXBElement.class;
private static final Class TARGET = Object.class;
private final TypeFactory typeFactory;
private final Parameter parameter;
private final Type returnType;
public JaxbElemToValue( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
this.parameter = typeFactory.createParameter( "element", JAXBElement.class );
this.returnType = typeFactory.getType( Object.class );
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "element", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
}
@Override
public boolean doGenericsMatch(Type sourceType, Type targetType) {
public boolean doTypeVarsMatch(Type sourceType, Type targetType) {
boolean match = false;
if (sourceType.getTypeParameters().size() == 1) {
match = sourceType.getTypeParameters().get( 0 ).equals( targetType );
@ -61,12 +48,12 @@ public class JaxbElemToValue extends BuiltInMappingMethod {
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Parameter getParameter() {
return parameter;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -18,11 +18,9 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.List;
import javax.xml.bind.JAXBElement;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -31,36 +29,24 @@ import org.mapstruct.ap.model.common.TypeFactory;
*
* @author Sjaak Derksen
*/
public class ListOfJaxbElemToListOfValue extends BuiltInMappingMethod {
public class ListOfJaxbElemToListOfValue extends BuiltInMethod {
private static final Class SOURCE = List.class;
private static final Class TARGET = List.class;
private static final Class TARGET_PARAM = JAXBElement.class;
private final TypeFactory typeFactory;
private final Parameter parameter;
private final Type returnType;
private final Type genericParam;
public ListOfJaxbElemToListOfValue( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
this.parameter = typeFactory.createParameter( "elementList", List.class );
this.returnType = typeFactory.getType( List.class );
this.genericParam = typeFactory.getType( JAXBElement.class ).erasure();
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "elementList", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
}
@Override
public boolean doGenericsMatch(Type sourceType, Type targetType) {
public boolean doTypeVarsMatch(Type sourceType, Type targetType) {
boolean match = false;
if ( ( sourceType.getTypeParameters().size() == 1 )
&& ( targetType.getTypeParameters().size() == 1 ) ) {
if ( ( sourceType.getTypeParameters().size() == 1 ) && ( targetType.getTypeParameters().size() == 1 ) ) {
Type typeParam = sourceType.getTypeParameters().get( 0 );
if ( typeParam.erasure().equals( typeFactory.getType( TARGET_PARAM ).erasure() ) &&
( typeParam.getTypeParameters().size() == 1 ) ) {
if ( typeParam.erasure().equals( genericParam ) && ( typeParam.getTypeParameters().size() == 1 ) ) {
match = typeParam.getTypeParameters().get( 0 ).equals( targetType.getTypeParameters().get( 0 ) );
}
}
@ -68,12 +54,12 @@ public class ListOfJaxbElemToListOfValue extends BuiltInMappingMethod {
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Parameter getParameter() {
return parameter;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -21,14 +21,12 @@ package org.mapstruct.ap.builtin;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.GregorianCalendar;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
@ -39,26 +37,18 @@ import static org.mapstruct.ap.util.Collections.asSet;
*
* @author Sjaak Derksen
*/
public class StringToXmlGregorianCalendar extends BuiltInMappingMethod {
public class StringToXmlGregorianCalendar extends BuiltInMethod {
private static final Class SOURCE = String.class;
private static final Class TARGET = XMLGregorianCalendar.class;
private final Parameter parameter;
private final Type returnType;
private final TypeFactory typeFactory;
private ConversionContext conversionContext;
public StringToXmlGregorianCalendar( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
}
this.parameter = typeFactory.createParameter( "date" , String.class );
this.returnType = typeFactory.getType( XMLGregorianCalendar.class );
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "date" , SOURCE ) } ),
typeFactory.getType( TARGET ),
getContextParm()
);
}
@Override
@ -72,21 +62,17 @@ public class StringToXmlGregorianCalendar extends BuiltInMappingMethod {
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Parameter getParameter() {
return parameter;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
@Override
public void setConversionContext(ConversionContext conversionContext) {
this.conversionContext = conversionContext;
}
private String getContextParm() {
public String getContextParameter(ConversionContext conversionContext) {
return conversionContext.getDateFormat() != null ? "\"" + conversionContext.getDateFormat() + "\"" : "null";
}
}

View File

@ -18,11 +18,9 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.Calendar;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -31,34 +29,23 @@ import org.mapstruct.ap.model.common.TypeFactory;
*
* @author Sjaak Derksen
*/
public class XmlGregorianCalendarToCalendar extends BuiltInMappingMethod {
public class XmlGregorianCalendarToCalendar extends BuiltInMethod {
private static final Class SOURCE = XMLGregorianCalendar.class;
private static final Class TARGET = Calendar.class;
private final TypeFactory typeFactory;
private final Parameter parameter;
private final Type returnType;
public XmlGregorianCalendarToCalendar( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
this.parameter = typeFactory.createParameter( "xcal", XMLGregorianCalendar.class );
this.returnType = typeFactory.getType( Calendar.class );
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "xcal", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
public Parameter getParameter() {
return parameter;
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -18,11 +18,9 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import java.util.Date;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
@ -31,34 +29,23 @@ import org.mapstruct.ap.model.common.TypeFactory;
*
* @author Sjaak Derksen
*/
public class XmlGregorianCalendarToDate extends BuiltInMappingMethod {
public class XmlGregorianCalendarToDate extends BuiltInMethod {
private static final Class SOURCE = XMLGregorianCalendar.class;
private static final Class TARGET = Date.class;
private final TypeFactory typeFactory;
private final Parameter parameter;
private final Type returnType;
public XmlGregorianCalendarToDate( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
this.parameter = typeFactory.createParameter( "xcal", XMLGregorianCalendar.class );
this.returnType = typeFactory.getType( Date.class );
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "xcal", SOURCE ) } ),
typeFactory.getType( TARGET ),
null
);
public Parameter getParameter() {
return parameter;
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
public Type getReturnType() {
return returnType;
}
}

View File

@ -18,10 +18,8 @@
*/
package org.mapstruct.ap.builtin;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import static java.util.Arrays.asList;
import org.mapstruct.ap.model.BuiltInMethod;
import javax.xml.datatype.XMLGregorianCalendar;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
@ -31,44 +29,28 @@ import org.mapstruct.ap.model.common.TypeFactory;
*
* @author Sjaak Derksen
*/
public class XmlGregorianCalendarToString extends BuiltInMappingMethod {
public class XmlGregorianCalendarToString extends BuiltInMethod {
private static final Class SOURCE = XMLGregorianCalendar.class;
private static final Class TARGET = String.class;
private final TypeFactory typeFactory;
private ConversionContext conversionContext;
private final Parameter parameter;
private final Type returnType;
public XmlGregorianCalendarToString( TypeFactory typeFactory ) {
this.typeFactory = typeFactory;
this.parameter = typeFactory.createParameter( "xcal" , XMLGregorianCalendar.class );
this.returnType = typeFactory.getType( String.class );
}
@Override
public MethodReference createMethodReference() {
return new MethodReference(
getName(),
asList( new Parameter[] { typeFactory.createParameter( "xcal" , SOURCE ) } ),
typeFactory.getType( TARGET ),
getContextParm()
);
public Parameter getParameter() {
return parameter;
}
@Override
public Type source() {
return typeFactory.getType( SOURCE ).erasure();
public Type getReturnType() {
return returnType;
}
@Override
public Type target() {
return typeFactory.getType( TARGET ).erasure();
}
@Override
public void setConversionContext(ConversionContext conversionContext) {
this.conversionContext = conversionContext;
}
private String getContextParm() {
public String getContextParameter(ConversionContext conversionContext) {
return conversionContext.getDateFormat() != null ? "\"" + conversionContext.getDateFormat() + "\"" : "null";
}
}

View File

@ -40,8 +40,7 @@ public interface ConversionProvider {
*
* @param sourceReference A reference to the source object, e.g.
* {@code beanName.getFoo()}.
* @param conversionContext ConversionContext providing optional information required for creating
the conversion.
* @param conversionContext ConversionContext providing optional information required for creating the conversion.
*
* @return A conversion from source to target.
*/
@ -52,8 +51,7 @@ public interface ConversionProvider {
*
* @param targetReference A reference to the targetReference object, e.g.
* {@code beanName.getFoo()}.
* @param conversionContext ConversionContext providing optional information required for creating
the conversion.
* @param conversionContext ConversionContext providing optional information required for creating the conversion.
*
* @return A conversion from target to source.
*/

View File

@ -1,112 +0,0 @@
/**
* Copyright 2012-2014 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.model;
import java.util.Collections;
import java.util.Set;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.util.Strings;
/**
* Implementations create:
* 1) an implementation of this build in method.
* 2) a reference to a build in method, to use in property mappings
* 3) a name for logging purposes.
*
* @author Sjaak Derksen
*/
public abstract class BuiltInMappingMethod extends ModelElement {
/**
* Creates a reference to the conversion method
*
* @return reference to method implementation
*/
public abstract MethodReference createMethodReference();
/**
* Sets the conversion context which is used to add context information such as date / time
* conversion pattern, etc.
*
* @param conversionContext ConversionContext providing optional information required for creating
the conversion.
*/
public void setConversionContext(ConversionContext conversionContext) { }
/**
* hashCode
*
* @return hashCode
*/
@Override
public int hashCode() {
return this.getClass().hashCode();
}
/**
* equals based on class
*
* @param obj other class
* @return true when classes are the same
*/
@Override
public boolean equals( Object obj ) {
if ( obj == null ) {
return false;
}
return ( getClass() == obj.getClass() );
}
/**
* tests whether generics do match. Default true.
*
* @param sourceType
* @param targetType
* @return
*/
public boolean doGenericsMatch( Type sourceType, Type targetType ) {
return true;
}
/**
* method name
* @return default method name is equal to class name of conversionmethod
*/
public String getName() {
return Strings.decapitalize( this.getClass().getSimpleName() );
}
/**
* imported types default. Only used types should be added. Source and Target types are coming via
* the MethodReference
*
* @return set of used types.
*/
@Override
public Set<Type> getImportTypes() {
return Collections.<Type>emptySet();
}
public abstract Type source();
public abstract Type target();
}

View File

@ -0,0 +1,166 @@
/**
* Copyright 2012-2014 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.model;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.mapstruct.ap.model.common.Accessibility;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.BasicMethod;
import org.mapstruct.ap.util.Strings;
/**
* Implementations create:
* 1) an implementation of this build in method.
* 2) a reference to a build in method, to use in property mappings
* 3) a name for logging purposes.
*
* @author Sjaak Derksen
*/
public abstract class BuiltInMethod extends ModelElement implements BasicMethod {
/**
* method name
* @return default method name is equal to class name of build in mehtod
*/
@Override
public String getName() {
return Strings.decapitalize( this.getClass().getSimpleName() );
}
/**
* imported types default. Only used types should be added. Source and Target types are coming via
* the MethodReference
*
* @return set of used types.
*/
@Override
public Set<Type> getImportTypes() {
return Collections.<Type>emptySet();
}
@Override
public boolean matches( Type sourceType, Type targetType ) {
if ( targetType.erasure().isAssignableTo( getReturnType().erasure() )
&& sourceType.erasure().isAssignableTo( getParameter().getType().erasure() ) ) {
return doTypeVarsMatch( sourceType, targetType );
}
return false;
}
/**
*
* @return all parameters are source parameters for build-in methods.
*/
@Override
public List<Parameter> getSourceParameters() {
return getParameters();
}
/**
* declaring mapper is always null, being the MapperImpl
* @return null
*/
@Override
public Type getDeclaringMapper() {
return null;
}
@Override
public List<Parameter> getParameters() {
return Arrays.asList( new Parameter[] { getParameter() } );
}
/**
* target parameter mechanism not supported for build-in-method
* @return null
*/
@Override
public Parameter getTargetParameter() {
return null;
}
/**
* the conversion context is used to format an auxiliary parameter in the method call
* with context specific information such as a date format.
*
* @param conversionContext
* @return null if no context parameter should be included
* "null" if there should be an explicit null call
* "'dateFormat'" for instance, to indicate how the build-in method should format the date
*/
public String getContextParameter(ConversionContext conversionContext) {
return null;
}
/**
* hashCode
*
* @return hashCode
*/
@Override
public int hashCode() {
return this.getClass().hashCode();
}
/**
* equals based on class
*
* @param obj other class
* @return true when classes are the same
*/
@Override
public boolean equals( Object obj ) {
if ( obj == null ) {
return false;
}
return ( getClass() == obj.getClass() );
}
/**
* Analyzes the Java Generics type variables in the parameter do match the type variables in the build in method
* same goes for the returnType.
*
* @param parameter source
* @param returnType target
* @return
*/
public boolean doTypeVarsMatch( Type parameter, Type returnType ) {
return true;
}
/**
* There's currently only one parameter foreseen instead of a list of parameter
*
* @return the parameter
*/
public abstract Parameter getParameter();
@Override
public Accessibility getAccessibility() {
return Accessibility.PRIVATE;
}
}

View File

@ -53,14 +53,14 @@ public class Mapper extends ModelElement {
private final List<Annotation> annotations;
private final List<MappingMethod> mappingMethods;
private final List<MapperReference> referencedMappers;
private final Set<BuiltInMappingMethod> builtInMethods;
private final Set<BuiltInMethod> builtInMethods;
private final boolean suppressGeneratorTimestamp;
private final Accessibility accessibility;
private Mapper(TypeFactory typeFactory, String packageName, boolean superTypeIsInterface, String interfaceName,
String implementationName, List<MappingMethod> mappingMethods,
List<MapperReference> referencedMappers, boolean suppressGeneratorTimestamp,
Set<BuiltInMappingMethod> builtInMethods, Accessibility accessibility) {
Set<BuiltInMethod> builtInMethods, Accessibility accessibility) {
this.packageName = packageName;
this.superTypeIsInterface = superTypeIsInterface;
this.interfaceName = interfaceName;
@ -80,7 +80,7 @@ public class Mapper extends ModelElement {
private TypeElement element;
private List<MappingMethod> mappingMethods;
private List<MapperReference> mapperReferences;
private Set<BuiltInMappingMethod> builtInMethods;
private Set<BuiltInMethod> builtInMethods;
private Elements elementUtils;
private boolean suppressGeneratorTimestamp;
@ -100,7 +100,7 @@ public class Mapper extends ModelElement {
return this;
}
public Builder builtInMethods(Set<BuiltInMappingMethod> builtInMethods) {
public Builder builtInMethods(Set<BuiltInMethod> builtInMethods) {
this.builtInMethods = builtInMethods;
return this;
}
@ -157,7 +157,7 @@ public class Mapper extends ModelElement {
addWithDependents( importedTypes, annotation.getType() );
}
for ( BuiltInMappingMethod builtInMethod : builtInMethods ) {
for ( BuiltInMethod builtInMethod : builtInMethods ) {
for ( Type type : builtInMethod.getImportTypes() ) {
addWithDependents( importedTypes, type );
}
@ -250,7 +250,7 @@ public class Mapper extends ModelElement {
return accessibility;
}
public Set<BuiltInMappingMethod> getBuiltInMethods() {
public Set<BuiltInMethod> getBuiltInMethods() {
return builtInMethods;
}
}

View File

@ -27,7 +27,7 @@ import org.mapstruct.ap.model.common.Accessibility;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.model.source.BasicMethod;
import org.mapstruct.ap.util.Strings;
/**
@ -43,7 +43,7 @@ public abstract class MappingMethod extends ModelElement {
private final Parameter targetParameter;
private final Accessibility accessibility;
protected MappingMethod(Method method) {
protected MappingMethod(BasicMethod method) {
this.name = method.getName();
this.parameters = method.getParameters();
this.returnType = method.getReturnType();

View File

@ -19,9 +19,8 @@
package org.mapstruct.ap.model;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.Method;
@ -36,16 +35,17 @@ public class MethodReference extends MappingMethod {
private final MapperReference declaringMapper;
private final String contextParam;
public MethodReference(Method method, MapperReference declaringMapper) {
public MethodReference(Method method, MapperReference declaringMapper ) {
super( method );
this.declaringMapper = declaringMapper;
this.contextParam = null;
this.contextParam = null;
}
public MethodReference(String name, List<Parameter> parameters, Type returnType, String contextParam ) {
super( name, parameters, returnType, null );
this.contextParam = contextParam;
public MethodReference(BuiltInMethod method, ConversionContext contextParam ) {
super( method );
this.declaringMapper = null;
this.contextParam = method.getContextParameter( contextParam );
}
public MapperReference getDeclaringMapper() {
@ -63,4 +63,11 @@ public class MethodReference extends MappingMethod {
public String getContextParam() {
return contextParam;
}
private String quoteParamWhenNotNull(String param) {
if (param != null ) {
return param != null ? "\"" + param + "\"" : "null";
}
return null;
}
}

View File

@ -0,0 +1,55 @@
/**
* Copyright 2012-2014 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.model.source;
import java.util.List;
import org.mapstruct.ap.model.common.Accessibility;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
/**
*
* @author Sjaak Derksen
*/
public interface BasicMethod {
/**
*
* @param sourceType
* @param targetType
* @return
*/
boolean matches( Type sourceType, Type targetType );
List<Parameter> getSourceParameters();
Type getDeclaringMapper();
String getName();
List<Parameter> getParameters();
Type getReturnType();
Parameter getTargetParameter();
Accessibility getAccessibility();
}

View File

@ -22,8 +22,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.util.Types;
import org.mapstruct.ap.model.common.Accessibility;
import org.mapstruct.ap.model.common.Parameter;
@ -40,7 +42,7 @@ import org.mapstruct.ap.util.Strings;
*
* @author Gunnar Morling
*/
public class Method {
public class Method implements BasicMethod {
private final Type declaringMapper;
private final ExecutableElement executable;
@ -48,6 +50,7 @@ public class Method {
private final Parameter targetParameter;
private final Type returnType;
private final Accessibility accessibility;
private final Types typeUtils;
private Map<String, List<Mapping>> mappings;
private IterableMapping iterableMapping;
@ -57,13 +60,22 @@ public class Method {
public static Method forMethodRequiringImplementation(ExecutableElement executable, List<Parameter> parameters,
Type returnType, Map<String, List<Mapping>> mappings,
IterableMapping iterableMapping, MapMapping mapMapping) {
IterableMapping iterableMapping, MapMapping mapMapping,
Types typeUtils ) {
return new Method( null, executable, parameters, returnType, mappings, iterableMapping, mapMapping );
return new Method(
null,
executable,
parameters,
returnType,
mappings,
iterableMapping,
mapMapping,
typeUtils );
}
public static Method forReferencedMethod(Type declaringMapper, ExecutableElement executable,
List<Parameter> parameters, Type returnType) {
List<Parameter> parameters, Type returnType, Types typeUtils ) {
return new Method(
declaringMapper,
@ -72,12 +84,13 @@ public class Method {
returnType,
Collections.<String, List<Mapping>>emptyMap(),
null,
null
null,
typeUtils
);
}
public static Method forFactoryMethod(Type declaringMapper, ExecutableElement executable,
Type returnType) {
Type returnType, Types typeUtils) {
return new Method(
declaringMapper,
@ -86,12 +99,14 @@ public class Method {
returnType,
Collections.<String, List<Mapping>>emptyMap(),
null,
null
null,
typeUtils
);
}
private Method(Type declaringMapper, ExecutableElement executable, List<Parameter> parameters, Type returnType,
Map<String, List<Mapping>> mappings, IterableMapping iterableMapping, MapMapping mapMapping) {
Map<String, List<Mapping>> mappings, IterableMapping iterableMapping, MapMapping mapMapping,
Types typeUtils ) {
this.declaringMapper = declaringMapper;
this.executable = executable;
this.parameters = parameters;
@ -102,6 +117,8 @@ public class Method {
this.accessibility = Accessibility.fromModifiers( executable.getModifiers() );
this.targetParameter = determineTargetParameter( parameters );
this.typeUtils = typeUtils;
}
private Parameter determineTargetParameter(Iterable<Parameter> parameters) {
@ -120,6 +137,7 @@ public class Method {
*
* @return The declaring mapper type
*/
@Override
public Type getDeclaringMapper() {
return declaringMapper;
}
@ -128,14 +146,17 @@ public class Method {
return executable;
}
@Override
public String getName() {
return executable.getSimpleName().toString();
}
@Override
public List<Parameter> getParameters() {
return parameters;
}
@Override
public List<Parameter> getSourceParameters() {
List<Parameter> sourceParameters = new ArrayList<Parameter>();
@ -162,6 +183,7 @@ public class Method {
return targetParameter != null ? targetParameter.getType() : returnType;
}
@Override
public Type getReturnType() {
return returnType;
}
@ -203,6 +225,7 @@ public class Method {
&& equals( getResultType(), method.getSourceParameters().iterator().next().getType() );
}
@Override
public Parameter getTargetParameter() {
return targetParameter;
}
@ -267,8 +290,23 @@ public class Method {
/**
* Whether an implementation of this method must be generated or not.
*
* @return true when an implementation is required
*/
public boolean requiresImplementation() {
return declaringMapper == null && executable.getModifiers().contains( Modifier.ABSTRACT );
}
/**
*
* @param sourceType
* @param targetType
* @return
*/
@Override
public boolean matches( Type sourceType, Type targetType ) {
MethodMatcher matcher = new MethodMatcher(typeUtils, this );
return matcher.matches( sourceType, targetType );
}
}

View File

@ -61,20 +61,31 @@ import org.mapstruct.ap.model.common.Type;
*/
public class MethodMatcher {
private final Type parameter;
private final Type returnType;
private final Method candidateMethod;
private final Types typeUtils;
private final Map<TypeVariable, TypeMirror> genericTypesMap = new HashMap<TypeVariable, TypeMirror>();
public MethodMatcher(Types typeUtils, Method candidateMethod, Type returnType, Type parameter) {
/**
* package scope constructor
*
* @param typeUtils
* @param candidateMethod
*/
MethodMatcher(Types typeUtils, Method candidateMethod) {
this.typeUtils = typeUtils;
this.candidateMethod = candidateMethod;
this.parameter = parameter;
this.returnType = returnType;
}
public boolean matches() {
/**
* package scoped method
*
* @param sourceType
* @param targetType
*
* @return true when both, sourceType and targetType matches the signature.
*/
boolean matches( Type sourceType, Type targetType ) {
// check & collect generic types.
List<? extends VariableElement> candidateParameters = candidateMethod.getExecutable().getParameters();
@ -83,14 +94,14 @@ public class MethodMatcher {
}
TypeMatcher parameterMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_FROM );
if ( !parameterMatcher.visit( candidateParameters.iterator().next().asType(), parameter.getTypeMirror() ) ) {
if ( !parameterMatcher.visit( candidateParameters.iterator().next().asType(), sourceType.getTypeMirror() ) ) {
return false;
}
// check return type
TypeMirror candidateReturnType = candidateMethod.getExecutable().getReturnType();
TypeMatcher returnTypeMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO );
if ( !returnTypeMatcher.visit( candidateReturnType, returnType.getTypeMirror() ) ) {
if ( !returnTypeMatcher.visit( candidateReturnType, targetType.getTypeMirror() ) ) {
return false;
}

View File

@ -41,7 +41,7 @@ import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.conversion.ConversionProvider;
import org.mapstruct.ap.conversion.Conversions;
import org.mapstruct.ap.model.common.DefaultConversionContext;
import org.mapstruct.ap.model.BuiltInMappingMethod;
import org.mapstruct.ap.model.BuiltInMethod;
import org.mapstruct.ap.builtin.BuiltInMappingMethods;
import org.mapstruct.ap.model.BeanMappingMethod;
import org.mapstruct.ap.model.DefaultMapperReference;
@ -56,9 +56,9 @@ import org.mapstruct.ap.model.TypeConversion;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
import org.mapstruct.ap.model.source.BasicMethod;
import org.mapstruct.ap.model.source.Mapping;
import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.model.source.MethodMatcher;
import org.mapstruct.ap.option.Options;
import org.mapstruct.ap.option.ReportingPolicy;
import org.mapstruct.ap.prism.MapperPrism;
@ -82,8 +82,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
private TypeFactory typeFactory;
private Conversions conversions;
private BuiltInMappingMethods builtInMethods;
private Set<BuiltInMappingMethod> usedBuiltInMethods;
private Set<BuiltInMethod> usedBuiltInMethods;
@Override
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<Method> sourceModel) {
@ -95,11 +94,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
this.typeFactory = context.getTypeFactory();
this.conversions = new Conversions( elementUtils, typeFactory );
this.builtInMethods = new BuiltInMappingMethods(messager, typeFactory );
this.usedBuiltInMethods = new HashSet<BuiltInMappingMethod>();
this.builtInMethods = new BuiltInMappingMethods(messager, typeFactory );
this.usedBuiltInMethods = new HashSet<BuiltInMappingMethod>();
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
this.usedBuiltInMethods = new HashSet<BuiltInMethod>();
return getMapper( mapperTypeElement, sourceModel );
}
@ -121,7 +117,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
.suppressGeneratorTimestamp( options.isSuppressGeneratorTimestamp() )
.typeFactory( typeFactory )
.elementUtils( elementUtils )
.builtInMethods( new HashSet<BuiltInMappingMethod>( usedBuiltInMethods ) )
.builtInMethods( new HashSet<BuiltInMethod>( usedBuiltInMethods ) )
.build();
usedBuiltInMethods.clear();
@ -129,7 +125,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
}
/**
* Returns the effective policy for reporting unmapped target properties. If
* Returns the effective policy for reporting unmapped getReturnType properties. If
* explicitly set via {@code Mapper}, this value will be returned. Otherwise
* the value from the corresponding processor option will be returned. If
* that is not set either, the default value from
@ -137,7 +133,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
*
* @param element The type declaring the generated mapper type
*
* @return The effective policy for reporting unmapped target properties.
* @return The effective policy for reporting unmapped getReturnType properties.
*/
private ReportingPolicy getEffectiveUnmappedTargetPolicy(TypeElement element) {
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
@ -570,15 +566,20 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
targetType = typeFactory.getReturnType( targetAcessor );
}
// first try the SourceMethods
String mappedElement = "property '" + Executables.getPropertyName( sourceAccessor ) + "'";
MethodReference propertyMappingMethod = getMappingMethodReference(
method,
"property '" + Executables.getPropertyName( sourceAccessor ) + "'",
mapperReferences,
methods,
sourceType,
targetType,
dateFormat
);
getBestMatch( method, mappedElement, methods, sourceType, targetType ),
mapperReferences );
// then try BuiltInMethods
if ( propertyMappingMethod == null ) {
propertyMappingMethod = getMappingMethodReference(
getBestMatch( method, mappedElement, builtInMethods, sourceType, targetType ),
targetType,
dateFormat );
}
TypeConversion conversion = getConversion(
sourceType,
targetType,
@ -622,16 +623,19 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
)
);
MethodReference elementMappingMethod =
getMappingMethodReference(
method,
"collection element",
mapperReferences,
methods,
sourceElementType,
targetElementType,
dateFormat
);
// first try the SourceMethods
MethodReference elementMappingMethod = getMappingMethodReference(
getBestMatch( method, "collection element", methods, sourceElementType, targetElementType ),
mapperReferences );
// then try BuiltInMethods
if ( elementMappingMethod == null ) {
elementMappingMethod = getMappingMethodReference(
getBestMatch( method, "collection element", builtInMethods, sourceElementType,
targetElementType ),
targetElementType,
dateFormat );
}
if ( !sourceElementType.isAssignableTo( targetElementType ) && conversion == null &&
elementMappingMethod == null ) {
@ -676,24 +680,30 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
"entry.getValue()"
);
// first try the SourceMethods
MethodReference keyMappingMethod = getMappingMethodReference(
method,
"map key",
mapperReferences,
methods,
sourceKeyType,
targetKeyType,
keyDateFormat
);
getBestMatch( method, "map key", methods, sourceKeyType, targetKeyType ), mapperReferences );
// then try BuiltInMethods
if ( keyMappingMethod == null ) {
keyMappingMethod = getMappingMethodReference(
getBestMatch( method, "map key", builtInMethods, sourceKeyType, targetKeyType ),
targetKeyType,
keyDateFormat );
}
// first try the SourceMethods
MethodReference valueMappingMethod = getMappingMethodReference(
method,
"map value",
mapperReferences,
methods,
sourceValueType,
targetValueType,
valueDateFormat
);
getBestMatch( method, "map value", methods, sourceValueType, targetValueType ),
mapperReferences );
// then try BuiltInMethods
if ( valueMappingMethod == null ) {
valueMappingMethod = getMappingMethodReference(
getBestMatch( method, "map value", builtInMethods, sourceValueType, targetValueType ),
targetValueType,
valueDateFormat );
}
if ( !sourceKeyType.isAssignableTo( targetKeyType ) && keyConversion == null && keyMappingMethod == null ) {
messager.printMessage(
@ -742,28 +752,26 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
private MethodReference getMappingMethodReference(Method mappingMethod, String mappedElement,
List<MapperReference> mapperReferences,
Iterable<Method> methods, Type parameterType,
Type returnType, String dateFormat) {
List<Method> candidatesWithMathingTargetType = new ArrayList<Method>();
private <T extends BasicMethod> T getBestMatch(Method mappingMethod, String mappedElement,
Iterable<T> methods, Type parameterType,
Type returnType) {
List<T> candidatesWithMathingTargetType = new ArrayList<T>();
for ( Method method : methods ) {
for ( T method : methods ) {
if ( method.getSourceParameters().size() != 1 ) {
continue;
}
MethodMatcher m = new MethodMatcher( typeUtils, method, returnType, parameterType );
if ( m.matches() ) {
if ( method.matches( parameterType, returnType ) ) {
candidatesWithMathingTargetType.add( method );
}
}
List<Method> candidatesWithBestMatchingSourceType = new ArrayList<Method>();
List<T> candidatesWithBestMatchingSourceType = new ArrayList<T>();
int bestMatchingSourceTypeDistance = Integer.MAX_VALUE;
// find the methods with the minimum distance regarding source parameter type
for ( Method method : candidatesWithMathingTargetType ) {
// find the methods with the minimum distance regarding getParameter getParameter type
for ( T method : candidatesWithMathingTargetType ) {
Parameter singleSourceParam = method.getSourceParameters().iterator().next();
int sourceTypeDistance = parameterType.distanceTo( singleSourceParam.getType() );
@ -776,7 +784,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
);
}
// print a warning if we find more than one method with minimum source type distance
// print a warning if we find more than one method with minimum getParameter type distance
if ( candidatesWithBestMatchingSourceType.size() > 1 ) {
messager.printMessage(
Kind.ERROR,
@ -791,32 +799,15 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
}
if ( !candidatesWithBestMatchingSourceType.isEmpty() ) {
Method method = candidatesWithBestMatchingSourceType.get( 0 );
MapperReference mapperReference = null;
return candidatesWithBestMatchingSourceType.get( 0 );
}
for ( MapperReference ref : mapperReferences ) {
if ( ref.getMapperType().equals( method.getDeclaringMapper() ) ) {
mapperReference = ref;
break;
}
}
return new MethodReference( method, mapperReference );
}
else {
BuiltInMappingMethod builtInMehtod = builtInMethods.getConversion( parameterType, returnType );
if (builtInMehtod != null ) {
ConversionContext context =
new DefaultConversionContext( typeFactory, returnType, dateFormat );
builtInMehtod.setConversionContext( context );
usedBuiltInMethods.add( builtInMehtod );
return builtInMehtod.createMethodReference();
}
}
return null;
}
private int addToCandidateListIfMinimal(List<Method> candidatesWithBestMathingType, int bestMatchingTypeDistance,
Method method, int currentTypeDistance) {
private <T extends BasicMethod> int addToCandidateListIfMinimal(List<T> candidatesWithBestMathingType,
int bestMatchingTypeDistance, T method, int currentTypeDistance) {
if ( currentTypeDistance == bestMatchingTypeDistance ) {
candidatesWithBestMathingType.add( method );
}
@ -829,6 +820,29 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
return bestMatchingTypeDistance;
}
private MethodReference getMappingMethodReference( Method method, List<MapperReference> mapperReferences ) {
if ( method != null ) {
MapperReference mapperReference = null;
for ( MapperReference ref : mapperReferences ) {
if ( ref.getMapperType().equals( method.getDeclaringMapper() ) ) {
mapperReference = ref;
break;
}
}
return new MethodReference( method, mapperReference );
}
return null;
}
private MethodReference getMappingMethodReference( BuiltInMethod method, Type returnType, String dateFormat ) {
if ( method != null ) {
usedBuiltInMethods.add( method );
ConversionContext ctx = new DefaultConversionContext( typeFactory, returnType, dateFormat );
return new MethodReference( method, ctx );
}
return null;
}
/**
* Reports an error if source the property can't be mapped from source to target. A mapping if possible if one of
* the following conditions is true:
@ -952,10 +966,10 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
}
/**
* A getter could be an alternative target-accessor if a setter is not available, and the
* target is a collection.
* A getter could be an alternative getReturnType-accessor if a setter is not available, and the
getReturnType is a collection.
*
* Provided such a getter is initialized lazy by the target class, e.g. in generated JAXB beans.
* Provided such a getter is initialized lazy by the getReturnType class, e.g. in generated JAXB beans.
*
* @param elements
*

View File

@ -46,6 +46,7 @@ import org.mapstruct.ap.prism.MappingsPrism;
import org.mapstruct.ap.util.AnnotationProcessingException;
import static javax.lang.model.util.ElementFilter.methodsIn;
import javax.lang.model.util.Types;
/**
* A {@link ModelElementProcessor} which retrieves a list of {@link Method}s
@ -59,12 +60,13 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
private Messager messager;
private TypeFactory typeFactory;
private Types typeUtils;
@Override
public List<Method> process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) {
this.messager = context.getMessager();
this.typeFactory = context.getTypeFactory();
this.typeUtils = context.getTypeUtils();
return retrieveMethods( mapperTypeElement, true );
}
@ -138,7 +140,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
returnType,
getMappings( method ),
IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ),
MapMapping.fromPrism( MapMappingPrism.getInstanceOn( method ) )
MapMapping.fromPrism( MapMappingPrism.getInstanceOn( method ) ),
typeUtils
);
}
else {
@ -152,7 +155,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
mapperRequiresImplementation ? null : typeFactory.getType( element ),
method,
parameters,
returnType
returnType,
typeUtils
);
}
//create factory method
@ -161,7 +165,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
Method.forFactoryMethod(
mapperRequiresImplementation ? null : typeFactory.getType( element ),
method,
returnType
returnType,
typeUtils
);
}
else {