#200 refactoring model, common interface for SimpleAssignment, TypeConversion and MethodReference, introducing decorators

This commit is contained in:
sjaakd 2014-04-14 21:47:18 +02:00
parent 909b5142b7
commit d412fd3e83
34 changed files with 907 additions and 538 deletions

View File

@ -18,7 +18,7 @@
*/ */
package org.mapstruct.ap.conversion; package org.mapstruct.ap.conversion;
import org.mapstruct.ap.model.TypeConversion; import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
/** /**
@ -37,22 +37,18 @@ public interface ConversionProvider {
/** /**
* Creates the conversion from source to target of a property mapping. * Creates the conversion from source to target of a property mapping.
* *
* @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. * @return A conversion from source to target.
*/ */
TypeConversion to(String sourceReference, ConversionContext conversionContext); Assignment to(ConversionContext conversionContext);
/** /**
* Creates the conversion from target to source of a property mapping. * Creates the conversion from target to source of a property mapping.
* *
* @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. * @return A conversion from target to source.
*/ */
TypeConversion from(String targetReference, ConversionContext conversionContext); Assignment from(ConversionContext conversionContext);
} }

View File

@ -20,11 +20,10 @@ package org.mapstruct.ap.conversion;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.TypeConversion; import org.mapstruct.ap.model.assignment.AssignmentFactory;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
@ -38,23 +37,21 @@ import static org.mapstruct.ap.util.Collections.asSet;
public class DateToStringConversion implements ConversionProvider { public class DateToStringConversion implements ConversionProvider {
@Override @Override
public TypeConversion to(String sourceReference, ConversionContext conversionContext) { public Assignment to(ConversionContext conversionContext) {
return new TypeConversion( return AssignmentFactory.createTypeConversion(
asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ), asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
Collections.<Type>emptyList(), Collections.<Type>emptySet(),
getOpenExpression( conversionContext, "format" ), getOpenExpression( conversionContext, "format" ),
sourceReference, getCloseExpression() );
getCloseExpression()
);
} }
@Override @Override
public TypeConversion from(String targetReference, ConversionContext conversionContext) { public Assignment from(ConversionContext conversionContext) {
return new TypeConversion( return AssignmentFactory.createTypeConversion(
asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ), asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
Arrays.asList( conversionContext.getTypeFactory().getType( ParseException.class ) ), asSet( conversionContext.getTypeFactory().getType( ParseException.class ) ),
getOpenExpression( conversionContext, "parse" ), getOpenExpression( conversionContext, "parse" ),
targetReference,
getCloseExpression() getCloseExpression()
); );
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.mapstruct.ap.conversion; package org.mapstruct.ap.conversion;
import org.mapstruct.ap.model.TypeConversion; import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
/** /**
@ -40,12 +40,12 @@ public class ReverseConversion implements ConversionProvider {
} }
@Override @Override
public TypeConversion to(String sourceReference, ConversionContext conversionContext) { public Assignment to( ConversionContext conversionContext) {
return conversionProvider.from( sourceReference, conversionContext ); return conversionProvider.from( conversionContext );
} }
@Override @Override
public TypeConversion from(String targetReference, ConversionContext conversionContext) { public Assignment from(ConversionContext conversionContext) {
return conversionProvider.to( targetReference, conversionContext ); return conversionProvider.to( conversionContext );
} }
} }

View File

@ -20,9 +20,10 @@ package org.mapstruct.ap.conversion;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.TypeConversion; import org.mapstruct.ap.model.assignment.AssignmentFactory;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.assignment.TypeConversion;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
/** /**
@ -33,24 +34,22 @@ import org.mapstruct.ap.model.common.Type;
public abstract class SimpleConversion implements ConversionProvider { public abstract class SimpleConversion implements ConversionProvider {
@Override @Override
public TypeConversion to(String sourceReference, ConversionContext conversionContext) { public Assignment to(ConversionContext conversionContext) {
ConversionExpression toExpressions = getToExpressions( conversionContext ); ConversionExpression toExpressions = getToExpressions( conversionContext );
return new TypeConversion( return AssignmentFactory.createTypeConversion(
getToConversionImportTypes( conversionContext ), getToConversionImportTypes( conversionContext ),
Collections.<Type>emptyList(), Collections.<Type>emptySet(),
toExpressions.getOpenExpression(), toExpressions.getOpenExpression(),
sourceReference,
toExpressions.getCloseExpression() ); toExpressions.getCloseExpression() );
} }
@Override @Override
public TypeConversion from(String targetReference, ConversionContext conversionContext) { public Assignment from(ConversionContext conversionContext) {
ConversionExpression fromExpressions = getFromExpressions( conversionContext ); ConversionExpression fromExpressions = getFromExpressions( conversionContext );
return new TypeConversion( return AssignmentFactory.createTypeConversion(
getFromConversionImportTypes( conversionContext ), getFromConversionImportTypes( conversionContext ),
Collections.<Type>emptyList(), Collections.<Type>emptySet(),
fromExpressions.getOpenExpression(), fromExpressions.getOpenExpression(),
targetReference,
fromExpressions.getCloseExpression() ); fromExpressions.getCloseExpression() );
} }

View File

@ -0,0 +1,40 @@
/**
* 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.Set;
import org.mapstruct.ap.model.common.Type;
/**
*
* @author Sjaak Derksen
*/
public interface Assignment {
Set<Type> getImportTypes();
Set<Type> getExceptionTypes();
void setAssignment( Assignment assignment );
String getSourceReference();
// TODO: tempfix..
boolean isSimple();
}

View File

@ -38,11 +38,11 @@ import org.mapstruct.ap.model.source.SourceMethod;
public class BeanMappingMethod extends MappingMethod { public class BeanMappingMethod extends MappingMethod {
private final List<PropertyMapping> propertyMappings; private final List<PropertyMapping> propertyMappings;
private final MethodReference factoryMethod; private final Factory factoryMethod;
public BeanMappingMethod(SourceMethod method, public BeanMappingMethod(SourceMethod method,
List<PropertyMapping> propertyMappings, List<PropertyMapping> propertyMappings,
MethodReference factoryMethod) { Factory factoryMethod) {
super( method ); super( method );
this.propertyMappings = propertyMappings; this.propertyMappings = propertyMappings;
this.factoryMethod = factoryMethod; this.factoryMethod = factoryMethod;
@ -78,7 +78,7 @@ public class BeanMappingMethod extends MappingMethod {
return types; return types;
} }
public MethodReference getFactoryMethod() { public Factory getFactoryMethod() {
return this.factoryMethod; return this.factoryMethod;
} }

View File

@ -0,0 +1,32 @@
/**
* 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.Set;
import org.mapstruct.ap.model.common.Type;
/**
*
* @author Sjaak Derksen
*/
public interface Factory {
Set<Type> getExceptionTypes();
}

View File

@ -33,11 +33,10 @@ import org.mapstruct.ap.util.Strings;
*/ */
public class IterableMappingMethod extends MappingMethod { public class IterableMappingMethod extends MappingMethod {
private final TargetAssignment elementAssignment; private final Assignment elementAssignment;
private final MethodReference factoryMethod; private final Factory factoryMethod;
public IterableMappingMethod(SourceMethod method, TargetAssignment parameterAssignment, public IterableMappingMethod(SourceMethod method, Assignment parameterAssignment, Factory factoryMethod) {
MethodReference factoryMethod) {
super( method ); super( method );
this.elementAssignment = parameterAssignment; this.elementAssignment = parameterAssignment;
this.factoryMethod = factoryMethod; this.factoryMethod = factoryMethod;
@ -53,7 +52,7 @@ public class IterableMappingMethod extends MappingMethod {
throw new IllegalStateException( "Method " + this + " has no source parameter." ); throw new IllegalStateException( "Method " + this + " has no source parameter." );
} }
public TargetAssignment getElementAssignment() { public Assignment getElementAssignment() {
return elementAssignment; return elementAssignment;
} }
@ -75,7 +74,7 @@ public class IterableMappingMethod extends MappingMethod {
); );
} }
public MethodReference getFactoryMethod() { public Factory getFactoryMethod() {
return this.factoryMethod; return this.factoryMethod;
} }
} }

View File

@ -33,12 +33,12 @@ import org.mapstruct.ap.util.Strings;
*/ */
public class MapMappingMethod extends MappingMethod { public class MapMappingMethod extends MappingMethod {
private final TargetAssignment keyAssignment; private final Assignment keyAssignment;
private final TargetAssignment valueAssignment; private final Assignment valueAssignment;
private final MethodReference factoryMethod; private final Factory factoryMethod;
public MapMappingMethod(SourceMethod method, TargetAssignment keyAssignment, TargetAssignment valueAssignment, public MapMappingMethod(SourceMethod method, Assignment keyAssignment, Assignment valueAssignment,
MethodReference factoryMethod) { Factory factoryMethod) {
super( method ); super( method );
this.keyAssignment = keyAssignment; this.keyAssignment = keyAssignment;
@ -56,11 +56,11 @@ public class MapMappingMethod extends MappingMethod {
throw new IllegalStateException( "Method " + this + " has no source parameter." ); throw new IllegalStateException( "Method " + this + " has no source parameter." );
} }
public TargetAssignment getKeyAssignment() { public Assignment getKeyAssignment() {
return keyAssignment; return keyAssignment;
} }
public TargetAssignment getValueAssignment() { public Assignment getValueAssignment() {
return valueAssignment; return valueAssignment;
} }
@ -99,7 +99,7 @@ public class MapMappingMethod extends MappingMethod {
); );
} }
public MethodReference getFactoryMethod() { public Factory getFactoryMethod() {
return this.factoryMethod; return this.factoryMethod;
} }

View File

@ -23,7 +23,6 @@ import java.util.Set;
import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.TargetAssignment.AssignmentType;
/** /**
* Represents the mapping between a source and target property, e.g. from * 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 * {@code String Source#foo} to {@code int Target#bar}. Name and type of source
@ -45,12 +44,12 @@ public class PropertyMapping extends ModelElement {
private final boolean isTargetAccessorSetter; private final boolean isTargetAccessorSetter;
private final String targetReadAccessorName; private final String targetReadAccessorName;
private final TargetAssignment propertyAssignment; private final Assignment propertyAssignment;
public PropertyMapping(String sourceBeanName, String sourceName, String sourceAccessorName, Type sourceType, public PropertyMapping(String sourceBeanName, String sourceName, String sourceAccessorName, Type sourceType,
String targetName, String targetAccessorName, Type targetType, String targetName, String targetAccessorName, Type targetType,
TargetAssignment propertyAssignment ) { Assignment propertyAssignment ) {
this.sourceBeanName = sourceBeanName; this.sourceBeanName = sourceBeanName;
this.sourceName = sourceName; this.sourceName = sourceName;
@ -95,7 +94,7 @@ public class PropertyMapping extends ModelElement {
return targetType; return targetType;
} }
public TargetAssignment getPropertyAssignment() { public Assignment getPropertyAssignment() {
return propertyAssignment; return propertyAssignment;
} }
@ -122,12 +121,12 @@ public class PropertyMapping extends ModelElement {
Set<Type> importTypes = new HashSet<Type>(); Set<Type> importTypes = new HashSet<Type>();
if ( propertyAssignment != null ) { if ( propertyAssignment != null ) {
if ( isTargetAccessorSetter() if ( isTargetAccessorSetter()
&& propertyAssignment.getAssignmentType().equals( AssignmentType.ASSIGNMENT ) && propertyAssignment.isSimple()
&& ( targetType.isCollectionType() || targetType.isMapType() ) ) { && ( targetType.isCollectionType() || targetType.isMapType() ) ) {
importTypes.addAll( targetType.getImportTypes() ); importTypes.addAll( targetType.getImportTypes() );
} }
if ( !propertyAssignment.getAssignmentType().equals( AssignmentType.ASSIGNMENT ) ) { if ( !propertyAssignment.isSimple() ) {
importTypes.addAll( propertyAssignment.getImportTypes() ); importTypes.addAll( propertyAssignment.getImportTypes() );
} }
} }

View File

@ -1,120 +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.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type;
/**
* This class carries the possible ways to do an assignment to a parameter on a mapping target
*
* The following options exist:
* <ol>
* <li>MethodReference</li>
* <li>TypeConversion</li>
* <li>Simple Assignment (empty TargetAssignment)</li>
* </ol>
*
* @author Sjaak Derksen
*/
public class TargetAssignment extends ModelElement {
public static enum AssignmentType { TYPE_CONVERSION, METHOD_REFERENCE, ASSIGNMENT };
private MethodReference methodReference;
private TypeConversion typeConversion;
private final AssignmentType assignmentType;
public TargetAssignment() {
assignmentType = AssignmentType.ASSIGNMENT;
}
public TargetAssignment( MethodReference methodReference ) {
assignmentType = AssignmentType.METHOD_REFERENCE;
this.methodReference = methodReference;
}
public TargetAssignment( TypeConversion typeConversion ) {
assignmentType = AssignmentType.TYPE_CONVERSION;
this.typeConversion = typeConversion;
}
public MethodReference getMethodReference() {
return methodReference;
}
public TypeConversion getTypeConversion() {
return typeConversion;
}
public AssignmentType getAssignmentType() {
return assignmentType;
}
public List<Type> getExceptionTypes() {
List<Type> exceptionTypes = new ArrayList<Type>();
switch ( assignmentType ) {
case METHOD_REFERENCE:
// exceptionTypes.addAll( methodReference.getExceptionTypes() );
break;
case TYPE_CONVERSION:
exceptionTypes.addAll( typeConversion.getExceptionTypes() );
break;
default:
}
return exceptionTypes;
}
@Override
public Set<Type> getImportTypes() {
Set<Type> importedTypes = new HashSet<Type>();
switch ( assignmentType ) {
case METHOD_REFERENCE:
importedTypes.addAll( methodReference.getImportTypes() );
break;
case TYPE_CONVERSION:
importedTypes.addAll( typeConversion.getImportTypes() );
break;
default:
}
return importedTypes;
}
@Override
public String toString() {
String result = "";
switch ( assignmentType ) {
case METHOD_REFERENCE:
result = methodReference.toString();
break;
case TYPE_CONVERSION:
result = typeConversion.toString();
break;
default:
}
return result;
}
}

View File

@ -0,0 +1,66 @@
/**
* 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.assignment;
import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type;
/**
*
* @author Sjaak Derksen
*/
public abstract class AssignmentDecorator extends ModelElement implements Assignment {
private final Assignment decoratedAssignment;
public AssignmentDecorator( Assignment decoratedAssignment ) {
this.decoratedAssignment = decoratedAssignment;
}
@Override
public Set<Type> getImportTypes() {
return decoratedAssignment.getImportTypes();
}
@Override
public Set<Type> getExceptionTypes() {
return decoratedAssignment.getExceptionTypes();
}
@Override
public void setAssignment( Assignment assignment ) {
decoratedAssignment.setAssignment( assignment );
}
public Assignment getAssignment() {
return decoratedAssignment;
}
@Override
public String getSourceReference() {
return decoratedAssignment.getSourceReference();
}
@Override
public boolean isSimple() {
return decoratedAssignment.isSimple();
}
}

View File

@ -0,0 +1,70 @@
/**
* 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.assignment;
import java.util.Collections;
import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.Factory;
import org.mapstruct.ap.model.MapperReference;
import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.SourceMethod;
import org.mapstruct.ap.model.source.builtin.BuiltInMethod;
/**
*
* @author Sjaak Derksen
*/
public class AssignmentFactory {
private AssignmentFactory() {
}
public static Assignment createTypeConversion( Set<Type> importTypes,
Set<Type> exceptionTypes,
String openExpression,
String closeExpression ) {
return new TypeConversion( importTypes, exceptionTypes, openExpression, closeExpression );
}
public static Assignment createTypeConversion( String openExpression, String closeExpression ) {
return new TypeConversion( Collections.<Type>emptySet(),
Collections.<Type>emptySet(),
openExpression,
closeExpression );
}
public static Factory createFactory(SourceMethod method, MapperReference declaringMapper) {
return new MethodReference( method, declaringMapper, null );
}
public static Assignment createAssignment(SourceMethod method, MapperReference declaringMapper, Type targetType) {
return new MethodReference(method, declaringMapper, targetType);
}
public static Assignment createAssignment( BuiltInMethod method, ConversionContext contextParam ) {
return new MethodReference( method, contextParam );
}
public static SimpleAssignment createAssignment( String sourceRef ) {
return new SimpleAssignment(sourceRef );
}
}

View File

@ -0,0 +1,32 @@
/**
* 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.assignment;
import org.mapstruct.ap.model.Assignment;
/**
*
* @author Sjaak Derksen
*/
public class LocalVarDecorator extends AssignmentDecorator {
public LocalVarDecorator( Assignment decoratedAssignment ) {
super( decoratedAssignment );
}
}

View File

@ -16,10 +16,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.model; package org.mapstruct.ap.model.assignment;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.Factory;
import org.mapstruct.ap.model.MapperReference;
import org.mapstruct.ap.model.MappingMethod;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Parameter;
@ -32,19 +37,11 @@ import org.mapstruct.ap.model.source.builtin.BuiltInMethod;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class MethodReference extends MappingMethod { public class MethodReference extends MappingMethod implements Assignment, Factory {
private final MapperReference declaringMapper; private final MapperReference declaringMapper;
private final Set<Type> importTypes; private final Set<Type> importTypes;
/**
* A reference to another mapping method or typeConversion in case this is a two-step mapping, e.g. from
* {@code JAXBElement<Bar>} to {@code Foo} to for which a nested method call will be generated:
* {@code setFoo(barToFoo( jaxbElemToValue( bar) ) )}
*/
private MethodReference methodRefChild;
private TypeConversion typeConversion;
/** /**
* In case this reference targets a built-in method, allows to pass specific context information to the invoked * In case this reference targets a built-in method, allows to pass specific context information to the invoked
* method. Currently this is only used to pass in the configured date format string when invoking a built-in method * method. Currently this is only used to pass in the configured date format string when invoking a built-in method
@ -52,6 +49,14 @@ public class MethodReference extends MappingMethod {
*/ */
private final String contextParam; private final String contextParam;
/**
* A reference to another mapping method or typeConversion in case this is a two-step mapping, e.g. from
* {@code JAXBElement<Bar>} to {@code Foo} to for which a nested method call will be generated:
* {@code setFoo(barToFoo( jaxbElemToValue( bar) ) )}
*/
private Assignment assignment;
/** /**
* Creates a new reference to the given method. * Creates a new reference to the given method.
* *
@ -88,6 +93,20 @@ public class MethodReference extends MappingMethod {
return contextParam; return contextParam;
} }
public Assignment getAssignment() {
return assignment;
}
@Override
public void setAssignment( Assignment assignment ) {
this.assignment = assignment;
}
@Override
public String getSourceReference() {
return assignment.getSourceReference();
}
/** /**
* @return the type of the single source parameter that is not the {@code @TargetType} parameter * @return the type of the single source parameter that is not the {@code @TargetType} parameter
*/ */
@ -100,32 +119,27 @@ public class MethodReference extends MappingMethod {
return null; return null;
} }
public void setMethodRefChild(MethodReference methodRefChild) {
this.methodRefChild = methodRefChild;
}
public MethodReference getMethodRefChild() {
return methodRefChild;
}
public void setTypeConversionChild( TypeConversion typeConversion ) {
this.typeConversion = typeConversion;
}
public TypeConversion getTypeConversion() {
return typeConversion;
}
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
Set<Type> imported = super.getImportTypes(); Set<Type> imported = new HashSet(super.getImportTypes());
imported.addAll( importTypes ); imported.addAll( importTypes );
if ( methodRefChild != null ) { if ( assignment != null ) {
imported.addAll( methodRefChild.getImportTypes() ); imported.addAll( assignment.getImportTypes() );
}
else if ( typeConversion != null ) {
imported.addAll( typeConversion.getImportTypes() );
} }
return imported; return imported;
} }
@Override
public Set<Type> getExceptionTypes() {
Set<Type> exceptions = new HashSet();
if ( assignment != null ) {
exceptions.addAll( assignment.getExceptionTypes() );
}
return exceptions;
}
@Override
public boolean isSimple() {
return false;
}
} }

View File

@ -0,0 +1,32 @@
/**
* 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.assignment;
import org.mapstruct.ap.model.Assignment;
/**
*
* @author Sjaak Derksen
*/
public class NewCollectionOrMapDecorator extends AssignmentDecorator {
public NewCollectionOrMapDecorator( Assignment decoratedAssignment ) {
super( decoratedAssignment );
}
}

View File

@ -0,0 +1,32 @@
/**
* 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.assignment;
import org.mapstruct.ap.model.Assignment;
/**
*
* @author Sjaak Derksen
*/
public class NullCheckDecorator extends AssignmentDecorator {
public NullCheckDecorator( Assignment decoratedAssignment ) {
super( decoratedAssignment );
}
}

View File

@ -0,0 +1,32 @@
/**
* 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.assignment;
import org.mapstruct.ap.model.Assignment;
/**
*
* @author Sjaak Derksen
*/
public class SetterDecorator extends AssignmentDecorator {
public SetterDecorator( Assignment decoratedAssignment ) {
super( decoratedAssignment );
}
}

View File

@ -0,0 +1,62 @@
/**
* 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.assignment;
import java.util.Collections;
import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type;
/**
*
* @author Sjaak Derksen
*/
public class SimpleAssignment extends ModelElement implements Assignment {
private final String sourceReference;
public SimpleAssignment( String sourceReference ) {
this.sourceReference = sourceReference;
}
@Override
public String getSourceReference() {
return sourceReference;
}
@Override
public Set<Type> getImportTypes() {
return Collections.emptySet();
}
@Override
public Set<Type> getExceptionTypes() {
return Collections.emptySet();
}
@Override
public void setAssignment( Assignment assignment ) {
throw new UnsupportedOperationException( "Not supported." );
}
public boolean isSimple() {
return true;
}
}

View File

@ -16,11 +16,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.model; package org.mapstruct.ap.model.assignment;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
@ -30,31 +30,30 @@ import org.mapstruct.ap.model.common.Type;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class TypeConversion extends ModelElement { public class TypeConversion extends ModelElement implements Assignment {
private final Set<Type> importTypes; private final Set<Type> importTypes;
private final List<Type> exceptionTypes; private final Set<Type> exceptionTypes;
private final String sourceReference;
private final String openExpression; private final String openExpression;
private final String closeExpression; private final String closeExpression;
/** /**
* A reference to mapping method in case this is a two-step mapping, e.g. from * A reference to mapping method in case this is a two-step mapping, e.g. from
* {@code JAXBElement<Bar>} to {@code Foo} to for which a nested method call will be generated: * {@code JAXBElement<Bar>} to {@code Foo} to for which a nested method call will be generated:
* {@code setFoo(barToFoo( jaxbElemToValue( bar) ) )} * {@code setFoo(barToFoo( jaxbElemToValue( bar) ) )}
*/ */
private MethodReference methodRefChild; private Assignment assignment;
public TypeConversion( Set<Type> importTypes,
List<Type> exceptionTypes, TypeConversion( Set<Type> importTypes,
Set<Type> exceptionTypes,
String openExpression, String openExpression,
String sourceReference,
String closeExpression ) { String closeExpression ) {
this.importTypes = new HashSet<Type>( importTypes ); this.importTypes = new HashSet<Type>( importTypes );
this.importTypes.addAll( exceptionTypes ); this.importTypes.addAll( exceptionTypes );
this.exceptionTypes = exceptionTypes; this.exceptionTypes = exceptionTypes;
this.openExpression = openExpression; this.openExpression = openExpression;
this.sourceReference = sourceReference;
this.closeExpression = closeExpression; this.closeExpression = closeExpression;
} }
@ -63,7 +62,8 @@ public class TypeConversion extends ModelElement {
return importTypes; return importTypes;
} }
public List<Type> getExceptionTypes() { @Override
public Set<Type> getExceptionTypes() {
return exceptionTypes; return exceptionTypes;
} }
@ -71,19 +71,26 @@ public class TypeConversion extends ModelElement {
return openExpression; return openExpression;
} }
public String getSourceReference() {
return sourceReference;
}
public String getCloseExpression() { public String getCloseExpression() {
return closeExpression; return closeExpression;
} }
public void setMethodRefChild( MethodReference methodRefChild ) { public Assignment getAssignment() {
this.methodRefChild = methodRefChild; return assignment;
} }
public MethodReference getMethodRefChild() { @Override
return methodRefChild; public String getSourceReference() {
return assignment.getSourceReference();
}
@Override
public void setAssignment( Assignment assignment ) {
this.assignment = assignment;
}
@Override
public boolean isSimple() {
return false;
} }
} }

View File

@ -0,0 +1,24 @@
/**
* 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.
*/
/**
* <p>
* Meta-model of assignments
* </p>
*/
package org.mapstruct.ap.model.assignment;

View File

@ -19,7 +19,6 @@
package org.mapstruct.ap.processor; package org.mapstruct.ap.processor;
import org.mapstruct.ap.processor.creation.MappingResolver; import org.mapstruct.ap.processor.creation.MappingResolver;
import org.mapstruct.ap.model.TargetAssignment;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -37,19 +36,25 @@ import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.BeanMappingMethod; import org.mapstruct.ap.model.BeanMappingMethod;
import org.mapstruct.ap.model.Decorator; import org.mapstruct.ap.model.Decorator;
import org.mapstruct.ap.model.DefaultMapperReference; import org.mapstruct.ap.model.DefaultMapperReference;
import org.mapstruct.ap.model.DelegatingMethod; import org.mapstruct.ap.model.DelegatingMethod;
import org.mapstruct.ap.model.EnumMappingMethod; import org.mapstruct.ap.model.EnumMappingMethod;
import org.mapstruct.ap.model.Factory;
import org.mapstruct.ap.model.IterableMappingMethod; import org.mapstruct.ap.model.IterableMappingMethod;
import org.mapstruct.ap.model.MapMappingMethod; import org.mapstruct.ap.model.MapMappingMethod;
import org.mapstruct.ap.model.Mapper; import org.mapstruct.ap.model.Mapper;
import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.model.MapperReference;
import org.mapstruct.ap.model.MappingMethod; import org.mapstruct.ap.model.MappingMethod;
import org.mapstruct.ap.model.MethodReference;
import org.mapstruct.ap.model.PropertyMapping; import org.mapstruct.ap.model.PropertyMapping;
import org.mapstruct.ap.model.assignment.AssignmentFactory;
import org.mapstruct.ap.model.assignment.NewCollectionOrMapDecorator;
import org.mapstruct.ap.model.assignment.LocalVarDecorator;
import org.mapstruct.ap.model.assignment.NullCheckDecorator;
import org.mapstruct.ap.model.assignment.SetterDecorator;
import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory; import org.mapstruct.ap.model.common.TypeFactory;
@ -316,9 +321,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
return mappingMethods; return mappingMethods;
} }
private MethodReference getFactoryMethod(List<MapperReference> mapperReferences, List<SourceMethod> methods, private Factory getFactoryMethod(List<MapperReference> mapperReferences, List<SourceMethod> methods,
Type returnType) { Type returnType) {
MethodReference result = null; Factory result = null;
for ( SourceMethod method : methods ) { for ( SourceMethod method : methods ) {
if ( !method.requiresImplementation() && !method.isIterableMapping() && !method.isMapMapping() if ( !method.requiresImplementation() && !method.isIterableMapping() && !method.isMapMapping()
&& method.getSourceParameters().size() == 0 ) { && method.getSourceParameters().size() == 0 ) {
@ -329,7 +334,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
if ( method.matches( parameterTypes, returnType ) ) { if ( method.matches( parameterTypes, returnType ) ) {
if ( result == null ) { if ( result == null ) {
MapperReference mapperReference = findMapperReference( mapperReferences, method ); MapperReference mapperReference = findMapperReference( mapperReferences, method );
result = new MethodReference( method, mapperReference, null ); result = AssignmentFactory.createFactory( method, mapperReference );
} }
else { else {
messager.printMessage( messager.printMessage(
@ -488,7 +493,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
mappedTargetProperties mappedTargetProperties
); );
MethodReference factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() ); Factory factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
return new BeanMappingMethod( method, propertyMappings, factoryMethod ); return new BeanMappingMethod( method, propertyMappings, factoryMethod );
} }
@ -631,7 +636,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
String dateFormat) { String dateFormat) {
Type sourceType = typeFactory.getReturnType( sourceAccessor ); Type sourceType = typeFactory.getReturnType( sourceAccessor );
Type targetType = null; Type targetType = null;
String conversionString = parameter.getName() + "." + sourceAccessor.getSimpleName().toString() + "()"; String sourceReference = parameter.getName() + "." + sourceAccessor.getSimpleName().toString() + "()";
if ( Executables.isSetterMethod( targetAcessor ) ) { if ( Executables.isSetterMethod( targetAcessor ) ) {
targetType = typeFactory.getSingleParameter( targetAcessor ).getType(); targetType = typeFactory.getSingleParameter( targetAcessor ).getType();
} }
@ -643,7 +648,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
String mappedElement = "property '" + Executables.getPropertyName( sourceAccessor ) + "'"; String mappedElement = "property '" + Executables.getPropertyName( sourceAccessor ) + "'";
TargetAssignment assignment = mappingResolver.getTargetAssignment( Assignment assignment = mappingResolver.getTargetAssignment(
method, method,
mappedElement, mappedElement,
mapperReferences, mapperReferences,
@ -652,34 +657,51 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
targetType, targetType,
targetPropertyName, targetPropertyName,
dateFormat, dateFormat,
conversionString sourceReference
); );
PropertyMapping property = new PropertyMapping( if ( assignment != null ) {
parameter.getName(),
Executables.getPropertyName( sourceAccessor ),
sourceAccessor.getSimpleName().toString(),
sourceType,
Executables.getPropertyName( targetAcessor ),
targetAcessor.getSimpleName().toString(),
targetType,
assignment
);
if ( !isPropertyMappable( property ) ) { // target accessor is setter, so decorate assigmment as setter
assignment = new SetterDecorator( assignment );
// create a new Map or Collection implementation if no method or type conversion
if ( targetType != null && ( targetType.isCollectionType() || targetType.isMapType() ) ) {
if ( assignment.isSimple() ) {
assignment = new NewCollectionOrMapDecorator( assignment );
}
}
// decorate assigment with null check of source can be null (is not primitive)
if ( !sourceType.isPrimitive() ) {
assignment = new NullCheckDecorator( assignment );
}
}
else {
messager.printMessage( messager.printMessage(
Kind.ERROR, Kind.ERROR,
String.format( String.format(
"Can't map property \"%s %s\" to \"%s %s\".", "Can't map property \"%s %s\" to \"%s %s\".",
property.getSourceType(), sourceType,
property.getSourceName(), Executables.getPropertyName( sourceAccessor ),
property.getTargetType(), targetType,
property.getTargetName() Executables.getPropertyName( targetAcessor )
), ),
method.getExecutable() method.getExecutable()
); );
} }
return property; return new PropertyMapping(
parameter.getName(),
Executables.getPropertyName( sourceAccessor ),
sourceAccessor.getSimpleName().toString(),
sourceType,
Executables.getPropertyName( targetAcessor ),
targetAcessor.getSimpleName().toString(),
targetType,
assignment
);
} }
private IterableMappingMethod getIterableMappingMethod(List<MapperReference> mapperReferences, private IterableMappingMethod getIterableMappingMethod(List<MapperReference> mapperReferences,
@ -690,7 +712,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
String dateFormat = method.getIterableMapping() != null ? method.getIterableMapping().getDateFormat() : null; String dateFormat = method.getIterableMapping() != null ? method.getIterableMapping().getDateFormat() : null;
String conversionStr = Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() ); String conversionStr = Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() );
TargetAssignment assignment = mappingResolver.getTargetAssignment( Assignment assignment = mappingResolver.getTargetAssignment(
method, method,
"collection element", "collection element",
mapperReferences, mapperReferences,
@ -714,7 +736,10 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
); );
} }
MethodReference factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() ); // target accessor is setter, so decorate assigmment as setter
assignment = new SetterDecorator( assignment );
Factory factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
return new IterableMappingMethod( method, assignment, factoryMethod ); return new IterableMappingMethod( method, assignment, factoryMethod );
} }
@ -728,7 +753,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
Type keyTargetType = resultTypeParams.get( 0 ); Type keyTargetType = resultTypeParams.get( 0 );
String keyDateFormat = method.getMapMapping() != null ? method.getMapMapping().getKeyFormat() : null; String keyDateFormat = method.getMapMapping() != null ? method.getMapMapping().getKeyFormat() : null;
TargetAssignment keyAssignment = mappingResolver.getTargetAssignment( Assignment keyAssignment = mappingResolver.getTargetAssignment(
method, method,
"map key", "map key",
mapperReferences, mapperReferences,
@ -757,7 +782,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
Type valueTargetType = resultTypeParams.get( 1 ); Type valueTargetType = resultTypeParams.get( 1 );
String valueDateFormat = method.getMapMapping() != null ? method.getMapMapping().getValueFormat() : null; String valueDateFormat = method.getMapMapping() != null ? method.getMapMapping().getValueFormat() : null;
TargetAssignment valueAssignment = mappingResolver.getTargetAssignment( Assignment valueAssignment = mappingResolver.getTargetAssignment(
method, method,
"map value", "map value",
mapperReferences, mapperReferences,
@ -781,7 +806,11 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
); );
} }
MethodReference factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() ); Factory factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
keyAssignment = new LocalVarDecorator( keyAssignment );
valueAssignment = new LocalVarDecorator( valueAssignment );
return new MapMappingMethod( method, keyAssignment, valueAssignment, factoryMethod ); return new MapMappingMethod( method, keyAssignment, valueAssignment, factoryMethod );
} }
@ -929,115 +958,4 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
} }
return null; return null;
} }
/**
* Whether the specified property can be mapped from source to target or not. A mapping if possible if one of
* the following conditions is true:
* <ul>
* <li>the source type is assignable to the target type</li>
* <li>a mapping method exists</li>
* <li>a built-in conversion exists</li>
* <li>the property is of a collection or map type and the constructor of the target type (either itself or its
* implementation type) accepts the source type.</li>
* </ul>
*
* @param property The property mapping to check.
*
* @return {@code true} if the specified property can be mapped, {@code false} otherwise.
*/
private boolean isPropertyMappable(PropertyMapping property) {
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
if ( property.getSourceType().isCollectionType() && property.getTargetType().isCollectionType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
property.getSourceType(),
property.getTargetType().getImplementationType() != null ?
property.getTargetType().getImplementationType() : property.getTargetType()
);
}
if ( property.getSourceType().isMapType() && property.getTargetType().isMapType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
property.getSourceType(),
property.getTargetType().getImplementationType() != null ?
property.getTargetType().getImplementationType() : property.getTargetType()
);
}
if ( property.getPropertyAssignment() != null ||
( ( property.getTargetType().isCollectionType() || property.getTargetType().isMapType() ) &&
collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
return true;
}
return false;
}
/**
* Whether the given target type has a single-argument constructor which accepts the given source type.
*
* @param sourceType the source type
* @param targetType the target type
*
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
// which accepts the source type
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ?
typeFactory.getType( Object.class ).getTypeMirror() :
sourceType.getTypeParameters().get( 0 ).getTypeMirror();
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty() ?
typeFactory.getType( Object.class ).getTypeMirror() :
targetType.getTypeParameters().get( 0 ).getTypeMirror();
return typeUtils.isAssignable( sourceElementType, targetElementType );
}
/**
* Whether the given target type has a single-argument constructor which accepts the given source type.
*
* @param sourceType the source type
* @param targetType the target type
*
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
// which accepts the source type
TypeMirror sourceKeyType = null;
TypeMirror targetKeyType = null;
TypeMirror sourceValueType = null;
TypeMirror targetValueType = null;
if ( sourceType.getTypeParameters().isEmpty() ) {
sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror();
sourceValueType = typeFactory.getType( Object.class ).getTypeMirror();
}
else {
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
sourceValueType = sourceType.getTypeParameters().get( 1 ).getTypeMirror();
}
if ( targetType.getTypeParameters().isEmpty() ) {
targetKeyType = typeFactory.getType( Object.class ).getTypeMirror();
targetValueType = typeFactory.getType( Object.class ).getTypeMirror();
}
else {
targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror();
targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror();
}
return typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
typeUtils.isAssignable( sourceValueType, targetValueType );
}
} }

View File

@ -18,22 +18,23 @@
*/ */
package org.mapstruct.ap.processor.creation; package org.mapstruct.ap.processor.creation;
import org.mapstruct.ap.model.TargetAssignment;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.annotation.processing.Messager; import javax.annotation.processing.Messager;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.conversion.ConversionProvider; import org.mapstruct.ap.conversion.ConversionProvider;
import org.mapstruct.ap.conversion.Conversions; import org.mapstruct.ap.conversion.Conversions;
import org.mapstruct.ap.model.Assignment;
import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.model.MapperReference;
import org.mapstruct.ap.model.MethodReference; import org.mapstruct.ap.model.assignment.SimpleAssignment;
import org.mapstruct.ap.model.TypeConversion;
import org.mapstruct.ap.model.VirtualMappingMethod; import org.mapstruct.ap.model.VirtualMappingMethod;
import org.mapstruct.ap.model.assignment.AssignmentFactory;
import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.ConversionContext;
import org.mapstruct.ap.model.common.DefaultConversionContext; import org.mapstruct.ap.model.common.DefaultConversionContext;
import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.Type;
@ -71,6 +72,7 @@ public class MappingResolver {
private final TypeFactory typeFactory; private final TypeFactory typeFactory;
private final Conversions conversions; private final Conversions conversions;
private final BuiltInMappingMethods builtInMethods; private final BuiltInMappingMethods builtInMethods;
private final Types typeUtils;
private final MethodSelectors methodSelectors; private final MethodSelectors methodSelectors;
/** /**
@ -87,6 +89,7 @@ public class MappingResolver {
this.builtInMethods = new BuiltInMappingMethods( typeFactory ); this.builtInMethods = new BuiltInMappingMethods( typeFactory );
this.virtualMethods = new HashSet<VirtualMappingMethod>(); this.virtualMethods = new HashSet<VirtualMappingMethod>();
this.methodSelectors = new MethodSelectors( typeUtils, typeFactory ); this.methodSelectors = new MethodSelectors( typeUtils, typeFactory );
this.typeUtils = typeUtils;
} }
@ -111,7 +114,7 @@ public class MappingResolver {
* <li>null, no assignment found</li> * <li>null, no assignment found</li>
* </ol> * </ol>
*/ */
public TargetAssignment getTargetAssignment( SourceMethod mappingMethod, public Assignment getTargetAssignment( SourceMethod mappingMethod,
String mappedElement, String mappedElement,
List<MapperReference> mapperReferences, List<MapperReference> mapperReferences,
List<SourceMethod> methods, List<SourceMethod> methods,
@ -174,52 +177,55 @@ public class MappingResolver {
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>(); this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
} }
private TargetAssignment getTargetAssignment( Type sourceType, Type targetType ) { private Assignment getTargetAssignment( Type sourceType, Type targetType ) {
// first simpele mapping method // first simpele mapping method
MethodReference mappingMethodReference = resolveViaMethod( sourceType, targetType ); Assignment referencedMethod = resolveViaMethod( sourceType, targetType );
if ( mappingMethodReference != null ) { if ( referencedMethod != null ) {
referencedMethod.setAssignment( AssignmentFactory.createAssignment( sourceReference ) );
context.virtualMethods.addAll( virtualMethodCandidates ); context.virtualMethods.addAll( virtualMethodCandidates );
return new TargetAssignment( mappingMethodReference ); return referencedMethod;
} }
// then direct assignable // then direct assignable
if ( sourceType.isAssignableTo( targetType ) ) { if ( sourceType.isAssignableTo( targetType ) || context.isPropertyMappable( sourceType, targetType ) ) {
return new TargetAssignment(); SimpleAssignment simpleAssignment = AssignmentFactory.createAssignment( sourceReference );
return simpleAssignment;
} }
// then type conversion // then type conversion
TypeConversion conversion = resolveViaConversion( sourceType, targetType ); Assignment conversion = resolveViaConversion( sourceType, targetType );
if ( conversion != null ) { if ( conversion != null ) {
return new TargetAssignment( conversion ); conversion.setAssignment( AssignmentFactory.createAssignment( sourceReference) );
return conversion;
} }
// 2 step method, first: method(method(souurce)) // 2 step method, first: method(method(souurce))
mappingMethodReference = resolveViaMethodAndMethod( sourceType, targetType ); referencedMethod = resolveViaMethodAndMethod( sourceType, targetType );
if ( mappingMethodReference != null ) { if ( referencedMethod != null ) {
context.virtualMethods.addAll( virtualMethodCandidates ); context.virtualMethods.addAll( virtualMethodCandidates );
return new TargetAssignment( mappingMethodReference ); return referencedMethod;
} }
// 2 step method, then: method(conversion(souurce)) // 2 step method, then: method(conversion(souurce))
mappingMethodReference = resolveViaConversionAndMethod( sourceType, targetType ); referencedMethod = resolveViaConversionAndMethod( sourceType, targetType );
if ( mappingMethodReference != null ) { if ( referencedMethod != null ) {
context.virtualMethods.addAll( virtualMethodCandidates ); context.virtualMethods.addAll( virtualMethodCandidates );
return new TargetAssignment( mappingMethodReference ); return referencedMethod;
} }
// 2 step method, finally: conversion(method(souurce)) // 2 step method, finally: conversion(method(souurce))
conversion = resolveViaMethodAndConversion( sourceType, targetType ); conversion = resolveViaMethodAndConversion( sourceType, targetType );
if ( conversion != null ) { if ( conversion != null ) {
context.virtualMethods.addAll( virtualMethodCandidates ); context.virtualMethods.addAll( virtualMethodCandidates );
return new TargetAssignment( conversion ); return conversion;
} }
// if nothing works, alas, the result is null // if nothing works, alas, the result is null
return null; return null;
} }
private TypeConversion resolveViaConversion( Type sourceType, Type targetType ) { private Assignment resolveViaConversion( Type sourceType, Type targetType ) {
ConversionProvider conversionProvider = context.conversions.getConversion( sourceType, targetType ); ConversionProvider conversionProvider = context.conversions.getConversion( sourceType, targetType );
@ -227,10 +233,9 @@ public class MappingResolver {
return null; return null;
} }
return conversionProvider.to( ConversionContext ctx = new DefaultConversionContext( context.typeFactory, targetType, dateFormat );
sourceReference, Assignment typeConversion = conversionProvider.to( ctx );
new DefaultConversionContext( context.typeFactory, targetType, dateFormat ) return typeConversion;
);
} }
/** /**
@ -238,7 +243,7 @@ public class MappingResolver {
* exists. * exists.
* *
*/ */
private MethodReference resolveViaMethod( Type sourceType, Type targetType ) { private Assignment resolveViaMethod( Type sourceType, Type targetType ) {
// first try to find a matching source method // first try to find a matching source method
SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType ); SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
@ -254,7 +259,9 @@ public class MappingResolver {
if ( matchingBuiltInMethod != null ) { if ( matchingBuiltInMethod != null ) {
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) ); virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
ConversionContext ctx = new DefaultConversionContext( context.typeFactory, targetType, dateFormat ); ConversionContext ctx = new DefaultConversionContext( context.typeFactory, targetType, dateFormat );
return new MethodReference( matchingBuiltInMethod, ctx ); Assignment methodReference = AssignmentFactory.createAssignment( matchingBuiltInMethod, ctx );
methodReference.setAssignment( AssignmentFactory.createAssignment( sourceReference ) );
return methodReference;
} }
return null; return null;
@ -270,12 +277,12 @@ public class MappingResolver {
* </ul> * </ul>
* then this method tries to resolve this combination and make a mapping methodY( methodX ( parameter ) ) * then this method tries to resolve this combination and make a mapping methodY( methodX ( parameter ) )
*/ */
private MethodReference resolveViaMethodAndMethod( Type sourceType, Type targetType ) { private Assignment resolveViaMethodAndMethod( Type sourceType, Type targetType ) {
List<Method> methodYCandidates = new ArrayList<Method>( methods ); List<Method> methodYCandidates = new ArrayList<Method>( methods );
methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() ); methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
MethodReference methodRefY = null; Assignment methodRefY = null;
// Iterate over all source methods. Check if the return type matches with the parameter that we need. // Iterate over all source methods. Check if the return type matches with the parameter that we need.
// so assume we need a method from A to C we look for a methodX from A to B (all methods in the // so assume we need a method from A to C we look for a methodX from A to B (all methods in the
@ -288,12 +295,13 @@ public class MappingResolver {
methodRefY = resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(), methodRefY = resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(),
targetType ); targetType );
if ( methodRefY != null ) { if ( methodRefY != null ) {
MethodReference methodRefX = resolveViaMethod( Assignment methodRefX = resolveViaMethod(
sourceType, sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType() methodYCandidate.getSourceParameters().get( 0 ).getType()
); );
if ( methodRefX != null ) { if ( methodRefX != null ) {
methodRefY.setMethodRefChild( methodRefX ); methodRefY.setAssignment( methodRefX );
methodRefX.setAssignment( AssignmentFactory.createAssignment( sourceReference ) );
break; break;
} }
else { else {
@ -315,12 +323,12 @@ public class MappingResolver {
* </ul> * </ul>
* then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) ) * then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) )
*/ */
private MethodReference resolveViaConversionAndMethod( Type sourceType, Type targetType ) { private Assignment resolveViaConversionAndMethod( Type sourceType, Type targetType ) {
List<Method> methodYCandidates = new ArrayList<Method>( methods ); List<Method> methodYCandidates = new ArrayList<Method>( methods );
methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() ); methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
MethodReference methodRefY = null; Assignment methodRefY = null;
for ( Method methodYCandidate : methodYCandidates ) { for ( Method methodYCandidate : methodYCandidates ) {
if ( methodYCandidate.getSourceParameters().size() == 1 ) { if ( methodYCandidate.getSourceParameters().size() == 1 ) {
@ -329,12 +337,13 @@ public class MappingResolver {
targetType targetType
); );
if ( methodRefY != null ) { if ( methodRefY != null ) {
TypeConversion conversionXRef = resolveViaConversion( Assignment conversionXRef = resolveViaConversion(
sourceType, sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType() methodYCandidate.getSourceParameters().get( 0 ).getType()
); );
if ( conversionXRef != null ) { if ( conversionXRef != null ) {
methodRefY.setTypeConversionChild( conversionXRef ); methodRefY.setAssignment( conversionXRef );
conversionXRef.setAssignment( new SimpleAssignment( sourceReference ) );
break; break;
} }
else { else {
@ -356,27 +365,25 @@ public class MappingResolver {
* </ul> * </ul>
* then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) ) * then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) )
*/ */
private TypeConversion resolveViaMethodAndConversion( Type sourceType, Type targetType ) { private Assignment resolveViaMethodAndConversion( Type sourceType, Type targetType ) {
List<Method> methodXCandidates = new ArrayList<Method>( methods ); List<Method> methodXCandidates = new ArrayList<Method>( methods );
methodXCandidates.addAll( context.builtInMethods.getBuiltInMethods() ); methodXCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
TypeConversion conversionYRef = null; Assignment conversionYRef = null;
// search the other way arround // search the other way arround
for ( Method methodXCandidate : methodXCandidates ) { for ( Method methodXCandidate : methodXCandidates ) {
if ( methodXCandidate.getSourceParameters().size() == 1 ) { if ( methodXCandidate.getSourceParameters().size() == 1 ) {
MethodReference methodRefX = resolveViaMethod( Assignment methodRefX = resolveViaMethod(
sourceType, sourceType,
methodXCandidate.getReturnType() methodXCandidate.getReturnType()
); );
if ( methodRefX != null ) { if ( methodRefX != null ) {
conversionYRef = resolveViaConversion( conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType );
methodXCandidate.getReturnType(),
targetType
);
if ( conversionYRef != null ) { if ( conversionYRef != null ) {
conversionYRef.setMethodRefChild( methodRefX ); conversionYRef.setAssignment( methodRefX );
methodRefX.setAssignment( new SimpleAssignment( sourceReference ) );
break; break;
} }
else { else {
@ -423,12 +430,12 @@ public class MappingResolver {
return null; return null;
} }
private MethodReference getMappingMethodReference( SourceMethod method, private Assignment getMappingMethodReference( SourceMethod method,
List<MapperReference> mapperReferences, List<MapperReference> mapperReferences,
Type targetType ) { Type targetType ) {
MapperReference mapperReference = findMapperReference( mapperReferences, method ); MapperReference mapperReference = findMapperReference( mapperReferences, method );
return new MethodReference( return AssignmentFactory.createAssignment(
method, method,
mapperReference, mapperReference,
SourceMethod.containsTargetTypeParameter( method.getParameters() ) ? targetType : null SourceMethod.containsTargetTypeParameter( method.getParameters() ) ? targetType : null
@ -444,4 +451,113 @@ public class MappingResolver {
return null; return null;
} }
} }
/**
* Whether the specified property can be mapped from source to target or not. A mapping if possible if one of
* the following conditions is true:
* <ul>
* <li>the source type is assignable to the target type</li>
* <li>a mapping method exists</li>
* <li>a built-in conversion exists</li>
* <li>the property is of a collection or map type and the constructor of the target type (either itself or its
* implementation type) accepts the source type.</li>
* </ul>
*
* @param property The property mapping to check.
*
* @return {@code true} if the specified property can be mapped, {@code false} otherwise.
*/
private boolean isPropertyMappable(Type sourceType, Type targetType) {
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
if ( sourceType.isCollectionType() && targetType.isCollectionType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
sourceType,
targetType.getImplementationType() != null ?
targetType.getImplementationType() : targetType
);
}
if ( sourceType.isMapType() && targetType.isMapType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
sourceType,
targetType.getImplementationType() != null ?
targetType.getImplementationType() : targetType
);
}
if ( ( ( targetType.isCollectionType() || targetType.isMapType() ) &&
collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
return true;
}
return false;
}
/**
* Whether the given target type has a single-argument constructor which accepts the given source type.
*
* @param sourceType the source type
* @param targetType the target type
*
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
// which accepts the source type
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ?
typeFactory.getType( Object.class ).getTypeMirror() :
sourceType.getTypeParameters().get( 0 ).getTypeMirror();
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty() ?
typeFactory.getType( Object.class ).getTypeMirror() :
targetType.getTypeParameters().get( 0 ).getTypeMirror();
return typeUtils.isAssignable( sourceElementType, targetElementType );
}
/**
* Whether the given target type has a single-argument constructor which accepts the given source type.
*
* @param sourceType the source type
* @param targetType the target type
*
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
// which accepts the source type
TypeMirror sourceKeyType = null;
TypeMirror targetKeyType = null;
TypeMirror sourceValueType = null;
TypeMirror targetValueType = null;
if ( sourceType.getTypeParameters().isEmpty() ) {
sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror();
sourceValueType = typeFactory.getType( Object.class ).getTypeMirror();
}
else {
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
sourceValueType = sourceType.getTypeParameters().get( 1 ).getTypeMirror();
}
if ( targetType.getTypeParameters().isEmpty() ) {
targetKeyType = typeFactory.getType( Object.class ).getTypeMirror();
targetValueType = typeFactory.getType( Object.class ).getTypeMirror();
}
else {
targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror();
targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror();
}
return typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
typeUtils.isAssignable( sourceValueType, targetValueType );
}
} }

View File

@ -32,7 +32,7 @@
</#if> </#if>
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) { for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) {
<@includeModel object=elementAssignment target="${resultName}.add" source="${loopVariableName}" targetType="${resultType.typeParameters[0].name}"/> <@includeModel object=elementAssignment target="${resultName}.add" targetType="${resultType.typeParameters[0].name}"/>
} }
<#if returnType.name != "void"> <#if returnType.name != "void">

View File

@ -36,13 +36,11 @@
<@includeModel object=keyAssignment <@includeModel object=keyAssignment
target=keyVariableName target=keyVariableName
targetType=typeName(resultType.typeParameters[0]) targetType=typeName(resultType.typeParameters[0])
source="entry.getKey()"
isLocalVar=true/> isLocalVar=true/>
<#-- value --> <#-- value -->
<@includeModel object=valueAssignment <@includeModel object=valueAssignment
target=valueVariableName target=valueVariableName
targetType=typeName(resultType.typeParameters[1]) targetType=typeName(resultType.typeParameters[1])
source="entry.getValue()"
isLocalVar=true/> isLocalVar=true/>
${resultName}.put( ${keyVariableName}, ${valueVariableName} ); ${resultName}.put( ${keyVariableName}, ${valueVariableName} );
} }

View File

@ -20,13 +20,7 @@
--> -->
<#if !( targetType.collectionType || targetType.mapType ) > <#if !( targetType.collectionType || targetType.mapType ) >
<#-- non collections or maps --> <#-- non collections or maps -->
<#if ( !sourceType.primitive && propertyAssignment.assignmentType!="ASSIGNMENT" ) > <@assignment aTargetType=targetType/>
if ( ${sourceBeanName}.${sourceAccessorName}() != null ) {
<@assignmentLine/>
}
<#else>
<@assignmentLine/>
</#if>
<#else> <#else>
<#-- collections or maps --> <#-- collections or maps -->
<#if ( ext.existingInstanceMapping || !targetAccessorSetter ) > <#if ( ext.existingInstanceMapping || !targetAccessorSetter ) >
@ -34,39 +28,19 @@
<#if ext.existingInstanceMapping> <#if ext.existingInstanceMapping>
${ext.targetBeanName}.${targetReadAccessorName}().clear(); ${ext.targetBeanName}.${targetReadAccessorName}().clear();
</#if><#t> </#if><#t>
if ( ${sourceBeanName}.${sourceAccessorName}() != null ) {
<#if targetType.collectionType> <#if targetType.collectionType>
<@collectionOrMapAssignmentLine target="${ext.targetBeanName}.${targetReadAccessorName}().addAll"/> <@assignment aTarget="${ext.targetBeanName}.${targetReadAccessorName}().addAll"/>
<#else> <#else>
<@collectionOrMapAssignmentLine target="${ext.targetBeanName}.${targetReadAccessorName}().putAll"/> <@assignment aTarget="${ext.targetBeanName}.${targetReadAccessorName}().putAll"/>
</#if> </#if>
}
} }
<#if targetAccessorSetter> <#if targetAccessorSetter>
else if ( ${sourceBeanName}.${sourceAccessorName}() != null ) { else <@assignment/>
<@collectionOrMapAssignmentLine/>
}
</#if> </#if>
<#elseif targetAccessorSetter> <#elseif targetAccessorSetter>
if ( ${sourceBeanName}.${sourceAccessorName}() != null ) { <@assignment/>
<@collectionOrMapAssignmentLine/>
}
</#if> </#if>
</#if> </#if>
<#macro collectionOrMapAssignmentLine <#macro assignment aTarget="${ext.targetBeanName}.${targetAccessorName}" aTargetType=targetType>
target="${ext.targetBeanName}.${targetAccessorName}" <@includeModel object=propertyAssignment target=aTarget targetType=aTargetType raw=true/>
source="${sourceBeanName}.${sourceAccessorName}">
<#compress>
<#if propertyAssignment?? && propertyAssignment.assignmentType!="ASSIGNMENT">
<@assignmentLine target source/>
<#else>
${target}( new <#if targetType.implementationType??><@includeModel object=targetType.implementationType/><#else><@includeModel object=targetType/></#if>( ${source}() ) );
</#if>
</#compress>
</#macro>
<#macro assignmentLine
target="${ext.targetBeanName}.${targetAccessorName}"
source="${sourceBeanName}.${sourceAccessorName}">
<@includeModel object=propertyAssignment target=target source="${source}()" targetType=targetType raw=true/>
</#macro> </#macro>

View File

@ -1,65 +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.
-->
<#if ( ext.isLocalVar?? && ext.isLocalVar==true )>
<#-- assignment is a local variable assignment -->
<#if (exceptionTypes?size == 0) >
${ext.targetType} ${ext.target} = <@assignment/>;
<#else>
${ext.targetType} ${ext.target};
try {
${ext.target} = <@assignment/>;
}
<#list exceptionTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
throw new RuntimeException( e );
}
</#list>
</#if>
<#else>
<#-- assignment is a method call -->
<#if (exceptionTypes?size == 0) >
${ext.target}( <@assignment/> );
<#else>
try {
${ext.target}( <@assignment/> );
}
<#list exceptionTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
throw new RuntimeException( e );
}
</#list>
</#if>
</#if>
<#macro assignment>
<#compress>
<#switch assignmentType>
<#case "TYPE_CONVERSION">
<@includeModel object=typeConversion source="${ext.source}" targetType=ext.targetType/>
<#break>
<#case "METHOD_REFERENCE">
<@includeModel object=methodReference source="${ext.source}" targetType=ext.targetType raw=ext.raw/>
<#break>
<#case "ASSIGNMENT">
${ext.source}
<#break>
</#switch>
</#compress>
</#macro>

View File

@ -0,0 +1,33 @@
<#--
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.
-->
<#if (exceptionTypes?size == 0) >
${ext.targetType} ${ext.target} = <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>;
<#else>
${ext.targetType} ${ext.target};
try {
${ext.target} = <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>;
}
<#list exceptionTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
throw new RuntimeException( e );
}
</#list>
</#if>

View File

@ -27,20 +27,11 @@
<#-- a class is passed on for casting, see @TargetType --> <#-- a class is passed on for casting, see @TargetType -->
${ext.targetType}.class ${ext.targetType}.class
<#else> <#else>
<#if methodRefChild??> <@includeModel object=assignment targetType=singleSourceParameterType raw=ext.raw/>
<#-- the nested case: another method -->
<@includeModel object=methodRefChild source=ext.source targetType=singleSourceParameterType.name/>
<#elseif typeConversion??>
<#-- the nested case: a type conversion -->
<@includeModel object=typeConversion source=ext.source targetType=singleSourceParameterType.name/>
<#else>
<#-- the non nested case -->
${ext.source}
</#if>
</#if> </#if>
<#if param_has_next>, </#if> <#if param_has_next>, </#if>
</#list> </#list>
<#-- context parameter, e.g. for buildin methods concerning date conversion --> <#-- context parameter, e.g. for builtin methods concerning date conversion -->
<#if contextParam??>, ${contextParam}</#if> <#if contextParam??>, ${contextParam}</#if>
</#macro> </#macro>
</@compress> </@compress>

View File

@ -18,10 +18,4 @@
limitations under the License. limitations under the License.
--> -->
<#if methodRefChild??> ${ext.target}( new <#if ext.targetType.implementationType??><@includeModel object=ext.targetType.implementationType/><#else><@includeModel object=ext.targetType/></#if>( ${sourceReference} ) );
<#-- the nested case: mapping method -->
${openExpression}<@includeModel object=methodRefChild source=ext.source targetType=ext.targetType/>${closeExpression}
<#else>
<#-- the non nested case: a type conversion -->
${openExpression}${sourceReference}${closeExpression}
</#if>

View File

@ -0,0 +1,23 @@
<#--
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.
-->
if ( ${sourceReference} != null ) {
<@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>
}

View File

@ -0,0 +1,32 @@
<#--
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.
-->
<#if (exceptionTypes?size == 0) >
${ext.target}( <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> );
<#else>
try {
${ext.target}( <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> );
}
<#list exceptionTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
throw new RuntimeException( e );
}
</#list>
</#if>

View File

@ -0,0 +1,21 @@
<#--
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.
-->
${sourceReference}

View File

@ -0,0 +1,21 @@
<#--
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.
-->
${openExpression}<@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>${closeExpression}