mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1406 targeting . as current object
This commit is contained in:
parent
f0a00eb0d5
commit
88a8669642
@ -232,6 +232,36 @@ public interface AddressMapper {
|
|||||||
|
|
||||||
In this case the source parameter is directly mapped into the target as the example above demonstrates. The parameter `hn`, a non bean type (in this case `java.lang.Integer`) is mapped to `houseNumber`.
|
In this case the source parameter is directly mapped into the target as the example above demonstrates. The parameter `hn`, a non bean type (in this case `java.lang.Integer`) is mapped to `houseNumber`.
|
||||||
|
|
||||||
|
[[mapping-nested-bean-properties-to-current-target]]
|
||||||
|
=== Mapping nested bean properties to current target
|
||||||
|
|
||||||
|
If you don't want explicitly name all properties from nested source bean, you can use `.` as target.
|
||||||
|
This will tell MapStruct to map every property from source bean to target object. The following shows an example:
|
||||||
|
|
||||||
|
.Nested multi mapping method
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
@Mapper
|
||||||
|
public interface CustomerMapper {
|
||||||
|
|
||||||
|
@Mapping(source = "record", target = ".")
|
||||||
|
Customer customerDtoToCustomer(CustomerDto customerDto);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
The generated code will map every property from `CustomerDto.record` to `Customer` directly, without need to manually name any of them.
|
||||||
|
|
||||||
|
Multi mapping notation can be very useful when mapping hierarchical objects to flat objects and opposite way.
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
If you need to send your domain object using JSON, one way to do this is to convert it to single object, where every parent class is represented as separate field in JSON.
|
||||||
|
And MapStruct allows you easily convert between these 2 types.
|
||||||
|
====
|
||||||
|
|
||||||
[[updating-bean-instances]]
|
[[updating-bean-instances]]
|
||||||
=== Updating existing bean instances
|
=== Updating existing bean instances
|
||||||
|
|
||||||
|
@ -26,6 +26,11 @@ import javax.tools.Diagnostic;
|
|||||||
import org.mapstruct.ap.internal.model.PropertyMapping.ConstantMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.ConstantMappingBuilder;
|
||||||
import org.mapstruct.ap.internal.model.PropertyMapping.JavaExpressionMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.JavaExpressionMappingBuilder;
|
||||||
import org.mapstruct.ap.internal.model.PropertyMapping.PropertyMappingBuilder;
|
import org.mapstruct.ap.internal.model.PropertyMapping.PropertyMappingBuilder;
|
||||||
|
import org.mapstruct.ap.internal.model.beanmapping.MappingReference;
|
||||||
|
import org.mapstruct.ap.internal.model.beanmapping.MappingReferences;
|
||||||
|
import org.mapstruct.ap.internal.model.beanmapping.PropertyEntry;
|
||||||
|
import org.mapstruct.ap.internal.model.beanmapping.SourceReference;
|
||||||
|
import org.mapstruct.ap.internal.model.beanmapping.TargetReference;
|
||||||
import org.mapstruct.ap.internal.model.common.BuilderType;
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
@ -34,14 +39,9 @@ import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer.GraphAnalyzerBui
|
|||||||
import org.mapstruct.ap.internal.model.source.BeanMapping;
|
import org.mapstruct.ap.internal.model.source.BeanMapping;
|
||||||
import org.mapstruct.ap.internal.model.source.Mapping;
|
import org.mapstruct.ap.internal.model.source.Mapping;
|
||||||
import org.mapstruct.ap.internal.model.source.MappingOptions;
|
import org.mapstruct.ap.internal.model.source.MappingOptions;
|
||||||
import org.mapstruct.ap.internal.model.beanmapping.MappingReference;
|
|
||||||
import org.mapstruct.ap.internal.model.beanmapping.MappingReferences;
|
|
||||||
import org.mapstruct.ap.internal.model.source.Method;
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
import org.mapstruct.ap.internal.model.beanmapping.PropertyEntry;
|
|
||||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||||
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
||||||
import org.mapstruct.ap.internal.model.beanmapping.SourceReference;
|
|
||||||
import org.mapstruct.ap.internal.model.beanmapping.TargetReference;
|
|
||||||
import org.mapstruct.ap.internal.prism.BeanMappingPrism;
|
import org.mapstruct.ap.internal.prism.BeanMappingPrism;
|
||||||
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
|
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
|
||||||
@ -200,6 +200,9 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
|
|
||||||
if ( !mappingReferences.isRestrictToDefinedMappings() ) {
|
if ( !mappingReferences.isRestrictToDefinedMappings() ) {
|
||||||
|
|
||||||
|
// apply name based mapping from a source reference
|
||||||
|
applyTargetThisMapping();
|
||||||
|
|
||||||
// map properties without a mapping
|
// map properties without a mapping
|
||||||
applyPropertyNameBasedMapping();
|
applyPropertyNameBasedMapping();
|
||||||
|
|
||||||
@ -650,6 +653,23 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
return errorOccured;
|
return errorOccured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When target this mapping present, iterates over unprocessed targets.
|
||||||
|
* <p>
|
||||||
|
* When a target property matches its name with the (nested) source property, it is added to the list if and
|
||||||
|
* only if it is an unprocessed target property.
|
||||||
|
*/
|
||||||
|
private void applyTargetThisMapping() {
|
||||||
|
if ( mappingReferences.getTargetThis() != null ) {
|
||||||
|
List<SourceReference> sourceRefs = mappingReferences.getTargetThis()
|
||||||
|
.getSourceReference()
|
||||||
|
.push( ctx.getTypeFactory(), ctx.getMessager(), method ).stream()
|
||||||
|
.filter( sr -> unprocessedTargetProperties.containsKey( sr.getDeepestPropertyName() ) )
|
||||||
|
.collect( Collectors.toList() );
|
||||||
|
applyPropertyNameBasedMapping( sourceRefs );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over all target properties and all source parameters.
|
* Iterates over all target properties and all source parameters.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -19,6 +19,7 @@ public class MappingReferences {
|
|||||||
private static final MappingReferences EMPTY = new MappingReferences( Collections.emptySet(), false );
|
private static final MappingReferences EMPTY = new MappingReferences( Collections.emptySet(), false );
|
||||||
|
|
||||||
private final Set<MappingReference> mappingReferences;
|
private final Set<MappingReference> mappingReferences;
|
||||||
|
private final MappingReference targetThis;
|
||||||
private final boolean restrictToDefinedMappings;
|
private final boolean restrictToDefinedMappings;
|
||||||
private final boolean forForgedMethods;
|
private final boolean forForgedMethods;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ public class MappingReferences {
|
|||||||
TypeFactory typeFactory) {
|
TypeFactory typeFactory) {
|
||||||
|
|
||||||
Set<MappingReference> references = new LinkedHashSet<>();
|
Set<MappingReference> references = new LinkedHashSet<>();
|
||||||
Set<MappingReference> targetThisReferences = new LinkedHashSet<>();
|
MappingReference targetThisReference = null;
|
||||||
|
|
||||||
for ( Mapping mapping : sourceMethod.getMappingOptions().getMappings() ) {
|
for ( Mapping mapping : sourceMethod.getMappingOptions().getMappings() ) {
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ public class MappingReferences {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// handle target reference
|
// handle target reference
|
||||||
TargetReference targetReference = new TargetReference.BuilderFromTargetMapping().mapping( mapping )
|
TargetReference targetReference = new TargetReference.Builder().mapping( mapping )
|
||||||
.method( sourceMethod )
|
.method( sourceMethod )
|
||||||
.messager( messager )
|
.messager( messager )
|
||||||
.typeFactory( typeFactory )
|
.typeFactory( typeFactory )
|
||||||
@ -51,22 +52,30 @@ public class MappingReferences {
|
|||||||
// add when inverse is also valid
|
// add when inverse is also valid
|
||||||
MappingReference mappingReference = new MappingReference( mapping, targetReference, sourceReference );
|
MappingReference mappingReference = new MappingReference( mapping, targetReference, sourceReference );
|
||||||
if ( isValidWhenInversed( mappingReference ) ) {
|
if ( isValidWhenInversed( mappingReference ) ) {
|
||||||
if ( targetReference.isTargetThis() ) {
|
if ( ".".equals( mapping.getTargetName() ) ) {
|
||||||
targetThisReferences.add( mappingReference );
|
targetThisReference = mappingReference;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
references.add( mappingReference );
|
references.add( mappingReference );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
references.addAll( targetThisReferences );
|
return new MappingReferences( references, targetThisReference, false );
|
||||||
return new MappingReferences( references, false );
|
}
|
||||||
|
|
||||||
|
public MappingReferences(Set<MappingReference> mappingReferences, MappingReference targetThis,
|
||||||
|
boolean restrictToDefinedMappings) {
|
||||||
|
this.mappingReferences = mappingReferences;
|
||||||
|
this.restrictToDefinedMappings = restrictToDefinedMappings;
|
||||||
|
this.forForgedMethods = restrictToDefinedMappings;
|
||||||
|
this.targetThis = targetThis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappingReferences(Set<MappingReference> mappingReferences, boolean restrictToDefinedMappings) {
|
public MappingReferences(Set<MappingReference> mappingReferences, boolean restrictToDefinedMappings) {
|
||||||
this.mappingReferences = mappingReferences;
|
this.mappingReferences = mappingReferences;
|
||||||
this.restrictToDefinedMappings = restrictToDefinedMappings;
|
this.restrictToDefinedMappings = restrictToDefinedMappings;
|
||||||
this.forForgedMethods = restrictToDefinedMappings;
|
this.forForgedMethods = restrictToDefinedMappings;
|
||||||
|
this.targetThis = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappingReferences(Set<MappingReference> mappingReferences, boolean restrictToDefinedMappings,
|
public MappingReferences(Set<MappingReference> mappingReferences, boolean restrictToDefinedMappings,
|
||||||
@ -74,6 +83,7 @@ public class MappingReferences {
|
|||||||
this.mappingReferences = mappingReferences;
|
this.mappingReferences = mappingReferences;
|
||||||
this.restrictToDefinedMappings = restrictToDefinedMappings;
|
this.restrictToDefinedMappings = restrictToDefinedMappings;
|
||||||
this.forForgedMethods = forForgedMethods;
|
this.forForgedMethods = forForgedMethods;
|
||||||
|
this.targetThis = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MappingReference> getMappingReferences() {
|
public Set<MappingReference> getMappingReferences() {
|
||||||
@ -117,6 +127,9 @@ public class MappingReferences {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MappingReference getTargetThis() {
|
||||||
|
return targetThis;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MapStruct filters automatically inversed invalid methods out. TODO: this is a principle we should discuss!
|
* MapStruct filters automatically inversed invalid methods out. TODO: this is a principle we should discuss!
|
||||||
@ -131,4 +144,5 @@ public class MappingReferences {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,9 @@ public class PropertyEntry {
|
|||||||
* @param type type of the property
|
* @param type type of the property
|
||||||
* @return the property entry for given parameters.
|
* @return the property entry for given parameters.
|
||||||
*/
|
*/
|
||||||
public static PropertyEntry forSourceReference(String name, Accessor readAccessor,
|
public static PropertyEntry forSourceReference(String[] name, Accessor readAccessor,
|
||||||
Accessor presenceChecker, Type type) {
|
Accessor presenceChecker, Type type) {
|
||||||
return new PropertyEntry( new String[]{name}, readAccessor, null, presenceChecker, type, null );
|
return new PropertyEntry( name, readAccessor, null, presenceChecker, type, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model.beanmapping;
|
package org.mapstruct.ap.internal.model.beanmapping;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.model.beanmapping.PropertyEntry.forSourceReference;
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.last;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
import javax.lang.model.element.AnnotationValue;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||||
@ -26,6 +25,9 @@ import org.mapstruct.ap.internal.util.Message;
|
|||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.model.beanmapping.PropertyEntry.forSourceReference;
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.last;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class describes the source side of a property mapping.
|
* This class describes the source side of a property mapping.
|
||||||
* <p>
|
* <p>
|
||||||
@ -55,18 +57,29 @@ public class SourceReference extends AbstractReference {
|
|||||||
*/
|
*/
|
||||||
public static class BuilderFromMapping {
|
public static class BuilderFromMapping {
|
||||||
|
|
||||||
private Mapping mapping;
|
|
||||||
private Method method;
|
private Method method;
|
||||||
private FormattingMessager messager;
|
private FormattingMessager messager = null;
|
||||||
private TypeFactory typeFactory;
|
private TypeFactory typeFactory;
|
||||||
|
|
||||||
|
private boolean isForwarded = false;
|
||||||
|
private Method templateMethod = null;
|
||||||
|
private String sourceName;
|
||||||
|
private AnnotationMirror annotationMirror;
|
||||||
|
private AnnotationValue sourceAnnotationValue;
|
||||||
|
|
||||||
public BuilderFromMapping messager(FormattingMessager messager) {
|
public BuilderFromMapping messager(FormattingMessager messager) {
|
||||||
this.messager = messager;
|
this.messager = messager;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BuilderFromMapping mapping(Mapping mapping) {
|
public BuilderFromMapping mapping(Mapping mapping) {
|
||||||
this.mapping = mapping;
|
this.sourceName = mapping.getSourceName();
|
||||||
|
this.annotationMirror = mapping.getMirror();
|
||||||
|
this.sourceAnnotationValue = mapping.getSourceAnnotationValue();
|
||||||
|
if ( mapping.getInheritContext() != null ) {
|
||||||
|
isForwarded = mapping.getInheritContext().isForwarded();
|
||||||
|
templateMethod = mapping.getInheritContext().getInheritedFromMethod();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +93,25 @@ public class SourceReference extends AbstractReference {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuilderFromMapping sourceName(String sourceName) {
|
||||||
|
this.sourceName = sourceName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public SourceReference build() {
|
public SourceReference build() {
|
||||||
|
|
||||||
String sourceName = mapping.getSourceName();
|
|
||||||
if ( sourceName == null ) {
|
if ( sourceName == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Objects.requireNonNull( messager );
|
||||||
|
|
||||||
String sourceNameTrimmed = sourceName.trim();
|
String sourceNameTrimmed = sourceName.trim();
|
||||||
if ( !sourceName.equals( sourceNameTrimmed ) ) {
|
if ( !sourceName.equals( sourceNameTrimmed ) ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
method.getExecutable(),
|
method.getExecutable(),
|
||||||
mapping.getMirror(),
|
annotationMirror,
|
||||||
mapping.getSourceAnnotationValue(),
|
sourceAnnotationValue,
|
||||||
Message.PROPERTYMAPPING_WHITESPACE_TRIMMED,
|
Message.PROPERTYMAPPING_WHITESPACE_TRIMMED,
|
||||||
sourceName,
|
sourceName,
|
||||||
sourceNameTrimmed
|
sourceNameTrimmed
|
||||||
@ -207,11 +226,7 @@ public class SourceReference extends AbstractReference {
|
|||||||
reportMappingError(
|
reportMappingError(
|
||||||
Message.PROPERTYMAPPING_INVALID_PARAMETER_NAME,
|
Message.PROPERTYMAPPING_INVALID_PARAMETER_NAME,
|
||||||
parameterName,
|
parameterName,
|
||||||
Strings.join(
|
Strings.join( method.getSourceParameters(), ", ", Parameter::getName )
|
||||||
method.getSourceParameters(),
|
|
||||||
", ",
|
|
||||||
Parameter::getName
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,8 +236,7 @@ public class SourceReference extends AbstractReference {
|
|||||||
private Parameter getSourceParameterFromMethodOrTemplate(String parameterName ) {
|
private Parameter getSourceParameterFromMethodOrTemplate(String parameterName ) {
|
||||||
|
|
||||||
Parameter result = null;
|
Parameter result = null;
|
||||||
if ( mapping.getInheritContext() != null && mapping.getInheritContext().isForwarded() ) {
|
if ( isForwarded ) {
|
||||||
Method templateMethod = mapping.getInheritContext().getInheritedFromMethod();
|
|
||||||
Parameter parameter = Parameter.getSourceParameter( templateMethod.getParameters(), parameterName );
|
Parameter parameter = Parameter.getSourceParameter( templateMethod.getParameters(), parameterName );
|
||||||
if ( parameter != null ) {
|
if ( parameter != null ) {
|
||||||
result = method.getSourceParameters()
|
result = method.getSourceParameters()
|
||||||
@ -260,8 +274,7 @@ public class SourceReference extends AbstractReference {
|
|||||||
);
|
);
|
||||||
elements.add( mostSimilarWord );
|
elements.add( mostSimilarWord );
|
||||||
reportMappingError(
|
reportMappingError(
|
||||||
Message.PROPERTYMAPPING_INVALID_PROPERTY_NAME, mapping.getSourceName(),
|
Message.PROPERTYMAPPING_INVALID_PROPERTY_NAME, sourceName, Strings.join( elements, "." )
|
||||||
Strings.join( elements, "." )
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,19 +282,22 @@ public class SourceReference extends AbstractReference {
|
|||||||
private List<PropertyEntry> matchWithSourceAccessorTypes(Type type, String[] entryNames) {
|
private List<PropertyEntry> matchWithSourceAccessorTypes(Type type, String[] entryNames) {
|
||||||
List<PropertyEntry> sourceEntries = new ArrayList<>();
|
List<PropertyEntry> sourceEntries = new ArrayList<>();
|
||||||
Type newType = type;
|
Type newType = type;
|
||||||
for ( String entryName : entryNames ) {
|
for ( int i = 0; i < entryNames.length; i++ ) {
|
||||||
boolean matchFound = false;
|
boolean matchFound = false;
|
||||||
Map<String, Accessor> sourceReadAccessors = newType.getPropertyReadAccessors();
|
Map<String, Accessor> sourceReadAccessors = newType.getPropertyReadAccessors();
|
||||||
Map<String, Accessor> sourcePresenceCheckers = newType.getPropertyPresenceCheckers();
|
Map<String, Accessor> sourcePresenceCheckers = newType.getPropertyPresenceCheckers();
|
||||||
|
|
||||||
for ( Map.Entry<String, Accessor> getter : sourceReadAccessors.entrySet() ) {
|
for ( Map.Entry<String, Accessor> getter : sourceReadAccessors.entrySet() ) {
|
||||||
if ( getter.getKey().equals( entryName ) ) {
|
if ( getter.getKey().equals( entryNames[i] ) ) {
|
||||||
newType = typeFactory.getReturnType(
|
newType = typeFactory.getReturnType(
|
||||||
(DeclaredType) newType.getTypeMirror(),
|
(DeclaredType) newType.getTypeMirror(),
|
||||||
getter.getValue()
|
getter.getValue()
|
||||||
);
|
);
|
||||||
sourceEntries.add( forSourceReference( entryName, getter.getValue(),
|
sourceEntries.add( forSourceReference(
|
||||||
sourcePresenceCheckers.get( entryName ), newType
|
Arrays.copyOf( entryNames, i + 1 ),
|
||||||
|
getter.getValue(),
|
||||||
|
sourcePresenceCheckers.get( entryNames[i] ),
|
||||||
|
newType
|
||||||
) );
|
) );
|
||||||
matchFound = true;
|
matchFound = true;
|
||||||
break;
|
break;
|
||||||
@ -295,9 +311,7 @@ public class SourceReference extends AbstractReference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reportMappingError(Message msg, Object... objects) {
|
private void reportMappingError(Message msg, Object... objects) {
|
||||||
messager.printMessage( method.getExecutable(), mapping.getMirror(), mapping.getSourceAnnotationValue(),
|
messager.printMessage( method.getExecutable(), annotationMirror, sourceAnnotationValue, msg, objects );
|
||||||
msg, objects
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +354,12 @@ public class SourceReference extends AbstractReference {
|
|||||||
public SourceReference build() {
|
public SourceReference build() {
|
||||||
List<PropertyEntry> sourcePropertyEntries = new ArrayList<>();
|
List<PropertyEntry> sourcePropertyEntries = new ArrayList<>();
|
||||||
if ( readAccessor != null ) {
|
if ( readAccessor != null ) {
|
||||||
sourcePropertyEntries.add( forSourceReference( name, readAccessor, presenceChecker, type ) );
|
sourcePropertyEntries.add( forSourceReference(
|
||||||
|
new String[] { name },
|
||||||
|
readAccessor,
|
||||||
|
presenceChecker,
|
||||||
|
type
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
return new SourceReference( sourceParameter, sourcePropertyEntries, true );
|
return new SourceReference( sourceParameter, sourcePropertyEntries, true );
|
||||||
}
|
}
|
||||||
@ -384,4 +403,24 @@ public class SourceReference extends AbstractReference {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SourceReference> push(TypeFactory typeFactory, FormattingMessager messager, Method method ) {
|
||||||
|
List<SourceReference> result = new ArrayList<>();
|
||||||
|
PropertyEntry deepestProperty = getDeepestProperty();
|
||||||
|
if ( deepestProperty != null ) {
|
||||||
|
Type type = deepestProperty.getType();
|
||||||
|
Map<String, Accessor> newDeepestReadAccessors = type.getPropertyReadAccessors();
|
||||||
|
for ( Map.Entry<String, Accessor> newDeepestReadAccessorEntry : newDeepestReadAccessors.entrySet() ) {
|
||||||
|
String newFullName = deepestProperty.getFullName() + "." + newDeepestReadAccessorEntry.getKey();
|
||||||
|
SourceReference sourceReference = new BuilderFromMapping()
|
||||||
|
.sourceName( newFullName )
|
||||||
|
.method( method )
|
||||||
|
.messager( messager )
|
||||||
|
.typeFactory( typeFactory )
|
||||||
|
.build();
|
||||||
|
result.add( sourceReference );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ package org.mapstruct.ap.internal.model.beanmapping;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
import javax.lang.model.element.AnnotationValue;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.BuilderType;
|
import org.mapstruct.ap.internal.model.common.BuilderType;
|
||||||
@ -56,13 +58,20 @@ public class TargetReference extends AbstractReference {
|
|||||||
/**
|
/**
|
||||||
* Builds a {@link TargetReference} from an {@code @Mappping}.
|
* Builds a {@link TargetReference} from an {@code @Mappping}.
|
||||||
*/
|
*/
|
||||||
public static class BuilderFromTargetMapping {
|
public static class Builder {
|
||||||
|
|
||||||
private Mapping mapping;
|
|
||||||
private Method method;
|
private Method method;
|
||||||
private FormattingMessager messager;
|
private FormattingMessager messager;
|
||||||
private TypeFactory typeFactory;
|
private TypeFactory typeFactory;
|
||||||
|
|
||||||
|
// mapping parameters
|
||||||
|
private boolean isReversed = false;
|
||||||
|
private boolean isIgnored = false;
|
||||||
|
private String targetName = null;
|
||||||
|
private AnnotationMirror annotationMirror = null;
|
||||||
|
private AnnotationValue targetAnnotationValue = null;
|
||||||
|
private AnnotationValue sourceAnnotationValue = null;
|
||||||
|
private Method templateMethod = null;
|
||||||
/**
|
/**
|
||||||
* During {@link #getTargetEntries(Type, String[])} an error can occur. However, we are invoking
|
* During {@link #getTargetEntries(Type, String[])} an error can occur. However, we are invoking
|
||||||
* that multiple times because the first entry can also be the name of the parameter. Therefore we keep
|
* that multiple times because the first entry can also be the name of the parameter. Therefore we keep
|
||||||
@ -70,31 +79,40 @@ public class TargetReference extends AbstractReference {
|
|||||||
*/
|
*/
|
||||||
private MappingErrorMessage errorMessage;
|
private MappingErrorMessage errorMessage;
|
||||||
|
|
||||||
public BuilderFromTargetMapping messager(FormattingMessager messager) {
|
public Builder messager(FormattingMessager messager) {
|
||||||
this.messager = messager;
|
this.messager = messager;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BuilderFromTargetMapping mapping(Mapping mapping) {
|
public Builder mapping(Mapping mapping) {
|
||||||
this.mapping = mapping;
|
if ( mapping.getInheritContext() != null ) {
|
||||||
|
this.isReversed = mapping.getInheritContext().isReversed();
|
||||||
|
this.templateMethod = mapping.getInheritContext().getInheritedFromMethod();
|
||||||
|
}
|
||||||
|
this.isIgnored = mapping.isIgnored();
|
||||||
|
this.targetName = mapping.getTargetName();
|
||||||
|
this.annotationMirror = mapping.getMirror();
|
||||||
|
this.targetAnnotationValue = mapping.getTargetAnnotationValue();
|
||||||
|
this.sourceAnnotationValue = mapping.getSourceAnnotationValue();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BuilderFromTargetMapping method(Method method) {
|
public Builder typeFactory(TypeFactory typeFactory) {
|
||||||
this.method = method;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BuilderFromTargetMapping typeFactory(TypeFactory typeFactory) {
|
|
||||||
this.typeFactory = typeFactory;
|
this.typeFactory = typeFactory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder method(Method method) {
|
||||||
|
this.method = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TargetReference build() {
|
public TargetReference build() {
|
||||||
|
|
||||||
boolean isInverse = mapping.getInheritContext() != null && mapping.getInheritContext().isReversed();
|
Objects.requireNonNull( method );
|
||||||
|
Objects.requireNonNull( typeFactory );
|
||||||
|
Objects.requireNonNull( messager );
|
||||||
|
|
||||||
String targetName = mapping.getTargetName();
|
|
||||||
if ( targetName == null ) {
|
if ( targetName == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -103,8 +121,8 @@ public class TargetReference extends AbstractReference {
|
|||||||
if ( !targetName.equals( targetNameTrimmed ) ) {
|
if ( !targetName.equals( targetNameTrimmed ) ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
method.getExecutable(),
|
method.getExecutable(),
|
||||||
mapping.getMirror(),
|
annotationMirror,
|
||||||
mapping.getTargetAnnotationValue(),
|
targetAnnotationValue,
|
||||||
Message.PROPERTYMAPPING_WHITESPACE_TRIMMED,
|
Message.PROPERTYMAPPING_WHITESPACE_TRIMMED,
|
||||||
targetName,
|
targetName,
|
||||||
targetNameTrimmed
|
targetNameTrimmed
|
||||||
@ -125,13 +143,13 @@ public class TargetReference extends AbstractReference {
|
|||||||
List<PropertyEntry> entries = getTargetEntries( resultType, targetPropertyNames );
|
List<PropertyEntry> entries = getTargetEntries( resultType, targetPropertyNames );
|
||||||
foundEntryMatch = (entries.size() == targetPropertyNames.length);
|
foundEntryMatch = (entries.size() == targetPropertyNames.length);
|
||||||
if ( !foundEntryMatch && segments.length > 1
|
if ( !foundEntryMatch && segments.length > 1
|
||||||
&& matchesSourceOrTargetParameter( segments[0], parameter, isInverse ) ) {
|
&& matchesSourceOrTargetParameter( segments[0], parameter, isReversed ) ) {
|
||||||
targetPropertyNames = Arrays.copyOfRange( segments, 1, segments.length );
|
targetPropertyNames = Arrays.copyOfRange( segments, 1, segments.length );
|
||||||
entries = getTargetEntries( resultType, targetPropertyNames );
|
entries = getTargetEntries( resultType, targetPropertyNames );
|
||||||
foundEntryMatch = (entries.size() == targetPropertyNames.length);
|
foundEntryMatch = (entries.size() == targetPropertyNames.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !foundEntryMatch && errorMessage != null && !isInverse ) {
|
if ( !foundEntryMatch && errorMessage != null && !isReversed ) {
|
||||||
// This is called only for reporting errors
|
// This is called only for reporting errors
|
||||||
errorMessage.report( );
|
errorMessage.report( );
|
||||||
}
|
}
|
||||||
@ -158,7 +176,7 @@ public class TargetReference extends AbstractReference {
|
|||||||
boolean isLast = i == entryNames.length - 1;
|
boolean isLast = i == entryNames.length - 1;
|
||||||
boolean isNotLast = i < entryNames.length - 1;
|
boolean isNotLast = i < entryNames.length - 1;
|
||||||
if ( isWriteAccessorNotValidWhenNotLast( targetWriteAccessor, isNotLast )
|
if ( isWriteAccessorNotValidWhenNotLast( targetWriteAccessor, isNotLast )
|
||||||
|| isWriteAccessorNotValidWhenLast( targetWriteAccessor, targetReadAccessor, mapping, isLast ) ) {
|
|| isWriteAccessorNotValidWhenLast( targetWriteAccessor, targetReadAccessor, isIgnored, isLast ) ) {
|
||||||
// there should always be a write accessor (except for the last when the mapping is ignored and
|
// there should always be a write accessor (except for the last when the mapping is ignored and
|
||||||
// there is a read accessor) and there should be read accessor mandatory for all but the last
|
// there is a read accessor) and there should be read accessor mandatory for all but the last
|
||||||
setErrorMessage( targetWriteAccessor, targetReadAccessor, entryNames, i, nextType );
|
setErrorMessage( targetWriteAccessor, targetReadAccessor, entryNames, i, nextType );
|
||||||
@ -232,14 +250,14 @@ public class TargetReference extends AbstractReference {
|
|||||||
private void setErrorMessage(Accessor targetWriteAccessor, Accessor targetReadAccessor, String[] entryNames,
|
private void setErrorMessage(Accessor targetWriteAccessor, Accessor targetReadAccessor, String[] entryNames,
|
||||||
int index, Type nextType) {
|
int index, Type nextType) {
|
||||||
if ( targetWriteAccessor == null && targetReadAccessor == null ) {
|
if ( targetWriteAccessor == null && targetReadAccessor == null ) {
|
||||||
errorMessage = new NoPropertyErrorMessage( mapping, method, messager, entryNames, index, nextType );
|
errorMessage = new NoPropertyErrorMessage( this, entryNames, index, nextType );
|
||||||
}
|
}
|
||||||
else if ( targetWriteAccessor == null ) {
|
else if ( targetWriteAccessor == null ) {
|
||||||
errorMessage = new NoWriteAccessorErrorMessage( mapping, method, messager );
|
errorMessage = new NoWriteAccessorErrorMessage(this );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//TODO there is no read accessor. What should we do here?
|
//TODO there is no read accessor. What should we do here?
|
||||||
errorMessage = new NoPropertyErrorMessage( mapping, method, messager, entryNames, index, nextType );
|
errorMessage = new NoPropertyErrorMessage( this, entryNames, index, nextType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,15 +301,15 @@ public class TargetReference extends AbstractReference {
|
|||||||
*
|
*
|
||||||
* @param writeAccessor that needs to be checked
|
* @param writeAccessor that needs to be checked
|
||||||
* @param readAccessor that is used
|
* @param readAccessor that is used
|
||||||
* @param mapping that is used
|
* @param isIgnored true when ignored
|
||||||
* @param isLast whether or not this is the last write accessor in the entry chain
|
* @param isLast whether or not this is the last write accessor in the entry chain
|
||||||
*
|
*
|
||||||
* @return {@code true} if the write accessor is not valid, {@code false} otherwise. See description for more
|
* @return {@code true} if the write accessor is not valid, {@code false} otherwise. See description for more
|
||||||
* information
|
* information
|
||||||
*/
|
*/
|
||||||
private static boolean isWriteAccessorNotValidWhenLast(Accessor writeAccessor, Accessor readAccessor,
|
private static boolean isWriteAccessorNotValidWhenLast(Accessor writeAccessor, Accessor readAccessor,
|
||||||
Mapping mapping, boolean isLast) {
|
boolean isIgnored, boolean isLast) {
|
||||||
return writeAccessor == null && isLast && ( readAccessor == null || !mapping.isIgnored() );
|
return writeAccessor == null && isLast && ( readAccessor == null || !isIgnored );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,7 +352,6 @@ public class TargetReference extends AbstractReference {
|
|||||||
private boolean matchesSourceOnInverseSourceParameter( String segment, boolean isInverse ) {
|
private boolean matchesSourceOnInverseSourceParameter( String segment, boolean isInverse ) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if ( isInverse ) {
|
if ( isInverse ) {
|
||||||
Method templateMethod = mapping.getInheritContext().getInheritedFromMethod();
|
|
||||||
// there is only source parameter by definition when applying @InheritInverseConfiguration
|
// there is only source parameter by definition when applying @InheritInverseConfiguration
|
||||||
Parameter inverseSourceParameter = first( templateMethod.getSourceParameters() );
|
Parameter inverseSourceParameter = first( templateMethod.getSourceParameters() );
|
||||||
result = inverseSourceParameter.getName().equals( segment );
|
result = inverseSourceParameter.getName().equals( segment );
|
||||||
@ -347,10 +364,6 @@ public class TargetReference extends AbstractReference {
|
|||||||
super( sourceParameter, targetPropertyEntries, isValid );
|
super( sourceParameter, targetPropertyEntries, isValid );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTargetThis() {
|
|
||||||
return getPropertyEntries().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TargetReference pop() {
|
public TargetReference pop() {
|
||||||
if ( getPropertyEntries().size() > 1 ) {
|
if ( getPropertyEntries().size() > 1 ) {
|
||||||
List<PropertyEntry> newPropertyEntries = new ArrayList<>( getPropertyEntries().size() - 1 );
|
List<PropertyEntry> newPropertyEntries = new ArrayList<>( getPropertyEntries().size() - 1 );
|
||||||
@ -368,34 +381,33 @@ public class TargetReference extends AbstractReference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private abstract static class MappingErrorMessage {
|
private abstract static class MappingErrorMessage {
|
||||||
private final Mapping mapping;
|
private final Builder builder;
|
||||||
private final Method method;
|
|
||||||
private final FormattingMessager messager;
|
|
||||||
|
|
||||||
private MappingErrorMessage(Mapping mapping, Method method, FormattingMessager messager) {
|
private MappingErrorMessage(Builder builder) {
|
||||||
this.mapping = mapping;
|
this.builder = builder;
|
||||||
this.method = method;
|
|
||||||
this.messager = messager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void report();
|
abstract void report();
|
||||||
|
|
||||||
protected void printErrorMessage(Message message, Object... args) {
|
protected void printErrorMessage(Message message, Object... args) {
|
||||||
Object[] errorArgs = new Object[args.length + 2];
|
Object[] errorArgs = new Object[args.length + 2];
|
||||||
errorArgs[0] = mapping.getTargetName();
|
errorArgs[0] = builder.targetName;
|
||||||
errorArgs[1] = method.getResultType();
|
errorArgs[1] = builder.method.getResultType();
|
||||||
System.arraycopy( args, 0, errorArgs, 2, args.length );
|
System.arraycopy( args, 0, errorArgs, 2, args.length );
|
||||||
AnnotationMirror annotationMirror = mapping.getMirror();
|
AnnotationMirror annotationMirror = builder.annotationMirror;
|
||||||
messager.printMessage( method.getExecutable(), annotationMirror, mapping.getSourceAnnotationValue(),
|
builder.messager.printMessage( builder.method.getExecutable(),
|
||||||
message, errorArgs
|
annotationMirror,
|
||||||
|
builder.sourceAnnotationValue,
|
||||||
|
message,
|
||||||
|
errorArgs
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NoWriteAccessorErrorMessage extends MappingErrorMessage {
|
private static class NoWriteAccessorErrorMessage extends MappingErrorMessage {
|
||||||
|
|
||||||
private NoWriteAccessorErrorMessage(Mapping mapping, Method method, FormattingMessager messager) {
|
private NoWriteAccessorErrorMessage(Builder builder) {
|
||||||
super( mapping, method, messager );
|
super( builder );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -410,9 +422,9 @@ public class TargetReference extends AbstractReference {
|
|||||||
private final int index;
|
private final int index;
|
||||||
private final Type nextType;
|
private final Type nextType;
|
||||||
|
|
||||||
private NoPropertyErrorMessage(Mapping mapping, Method method, FormattingMessager messager,
|
private NoPropertyErrorMessage(Builder builder, String[] entryNames, int index,
|
||||||
String[] entryNames, int index, Type nextType) {
|
Type nextType) {
|
||||||
super( mapping, method, messager );
|
super( builder );
|
||||||
this.entryNames = entryNames;
|
this.entryNames = entryNames;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.nextType = nextType;
|
this.nextType = nextType;
|
||||||
|
@ -154,7 +154,6 @@ public enum Message {
|
|||||||
VALUEMAPPING_ANY_AREADY_DEFINED( "Source = \"<ANY_REMAINING>\" or \"<ANY_UNMAPPED>\" can only be used once." ),
|
VALUEMAPPING_ANY_AREADY_DEFINED( "Source = \"<ANY_REMAINING>\" or \"<ANY_UNMAPPED>\" can only be used once." ),
|
||||||
VALUE_MAPPING_UNMAPPED_SOURCES( "The following constants from the %s enum have no corresponding constant in the %s enum and must be be mapped via adding additional mappings: %s." ),
|
VALUE_MAPPING_UNMAPPED_SOURCES( "The following constants from the %s enum have no corresponding constant in the %s enum and must be be mapped via adding additional mappings: %s." ),
|
||||||
VALUEMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s." );
|
VALUEMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s." );
|
||||||
|
|
||||||
// CHECKSTYLE:ON
|
// CHECKSTYLE:ON
|
||||||
|
|
||||||
private final String description;
|
private final String description;
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
public class CustomerDTO {
|
||||||
|
private String name;
|
||||||
|
private int level;
|
||||||
|
private ItemDTO item;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemDTO getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItem(ItemDTO item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(int level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
public class CustomerItem {
|
||||||
|
private String id;
|
||||||
|
private int status;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
public class ItemDTO {
|
||||||
|
private String id;
|
||||||
|
private int status;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface NestedMapper {
|
||||||
|
|
||||||
|
NestedMapper INSTANCE = Mappers.getMapper( NestedMapper.class );
|
||||||
|
|
||||||
|
@Mapping( target = ".", source = "customer.item" )
|
||||||
|
OrderItem map(OrderDTO order);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
public class OrderDTO {
|
||||||
|
|
||||||
|
private ItemDTO item;
|
||||||
|
|
||||||
|
private CustomerDTO customer;
|
||||||
|
|
||||||
|
public ItemDTO getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItem(ItemDTO item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomer( CustomerDTO customer ) {
|
||||||
|
this.customer = customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomerDTO getCustomer() {
|
||||||
|
return this.customer;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
public class OrderItem {
|
||||||
|
private String id;
|
||||||
|
private int status;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SimpleMapper {
|
||||||
|
SimpleMapper INSTANCE = Mappers.getMapper( SimpleMapper.class );
|
||||||
|
|
||||||
|
@Mapping( target = ".", source = "item" )
|
||||||
|
@Mapping( target = "name", ignore = true )
|
||||||
|
CustomerItem map(CustomerDTO customer);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SimpleMapperWithIgnore {
|
||||||
|
SimpleMapperWithIgnore INSTANCE = Mappers.getMapper( SimpleMapperWithIgnore.class );
|
||||||
|
|
||||||
|
@Mapping( target = ".", source = "item" )
|
||||||
|
@Mapping( target = "id", ignore = true )
|
||||||
|
CustomerItem map(CustomerDTO customer);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.targetthis;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
@WithClasses( {
|
||||||
|
OrderDTO.class,
|
||||||
|
CustomerDTO.class,
|
||||||
|
CustomerItem.class,
|
||||||
|
CustomerItem.class,
|
||||||
|
ItemDTO.class,
|
||||||
|
OrderItem.class,
|
||||||
|
OrderDTO.class
|
||||||
|
} )
|
||||||
|
public class TargetThisMappingTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithClasses( SimpleMapper.class )
|
||||||
|
public void testTargetingThis() {
|
||||||
|
CustomerDTO ce = new CustomerDTO();
|
||||||
|
ce.setName( "customer name" );
|
||||||
|
|
||||||
|
ItemDTO e = new ItemDTO();
|
||||||
|
e.setId( "item id" );
|
||||||
|
e.setStatus( 1 );
|
||||||
|
ce.setItem( e );
|
||||||
|
|
||||||
|
CustomerItem c = SimpleMapper.INSTANCE.map( ce );
|
||||||
|
|
||||||
|
assertThat( c ).isNotNull();
|
||||||
|
assertThat( c.getName() ).isNull();
|
||||||
|
assertThat( c.getId() ).isEqualTo( ce.getItem().getId() );
|
||||||
|
assertThat( c.getStatus() ).isEqualTo( ce.getItem().getStatus() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithClasses( NestedMapper.class )
|
||||||
|
public void testTargetingThisWithNestedLevels() {
|
||||||
|
CustomerDTO customerDTO = new CustomerDTO();
|
||||||
|
customerDTO.setName( "customer name" );
|
||||||
|
|
||||||
|
ItemDTO itemDTO = new ItemDTO();
|
||||||
|
itemDTO.setId( "item id" );
|
||||||
|
itemDTO.setStatus( 1 );
|
||||||
|
customerDTO.setItem( itemDTO );
|
||||||
|
|
||||||
|
OrderDTO order = new OrderDTO();
|
||||||
|
order.setCustomer( customerDTO );
|
||||||
|
|
||||||
|
OrderItem c = NestedMapper.INSTANCE.map( order );
|
||||||
|
|
||||||
|
assertThat( c ).isNotNull();
|
||||||
|
assertThat( c.getId() ).isEqualTo( customerDTO.getItem().getId() );
|
||||||
|
assertThat( c.getStatus() ).isEqualTo( customerDTO.getItem().getStatus() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithClasses( SimpleMapperWithIgnore.class )
|
||||||
|
public void testTargetingThisWithIgnore() {
|
||||||
|
CustomerDTO ce = new CustomerDTO();
|
||||||
|
ce.setName( "customer name" );
|
||||||
|
|
||||||
|
ItemDTO e = new ItemDTO();
|
||||||
|
e.setId( "item id" );
|
||||||
|
e.setStatus( 1 );
|
||||||
|
ce.setItem( e );
|
||||||
|
|
||||||
|
CustomerItem c = SimpleMapperWithIgnore.INSTANCE.map( ce );
|
||||||
|
|
||||||
|
assertThat( c ).isNotNull();
|
||||||
|
assertThat( c.getName() ).isEqualTo( "customer name" );
|
||||||
|
assertThat( c.getId() ).isNull();
|
||||||
|
assertThat( c.getStatus() ).isEqualTo( ce.getItem().getStatus() );
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.annotation.processing.Processor;
|
import javax.annotation.processing.Processor;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
@ -119,7 +120,7 @@ class JdkCompilingStatement extends CompilingStatement {
|
|||||||
if ( diag.getKind() != Kind.ERROR
|
if ( diag.getKind() != Kind.ERROR
|
||||||
|| previous == null
|
|| previous == null
|
||||||
|| !previous.getSourceFileName().equals( diag.getSourceFileName() )
|
|| !previous.getSourceFileName().equals( diag.getSourceFileName() )
|
||||||
|| !previous.getLine().equals( diag.getLine() ) ) {
|
|| !Objects.equals( previous.getLine(), diag.getLine() ) ) {
|
||||||
filtered.add( diag );
|
filtered.add( diag );
|
||||||
previous = diag;
|
previous = diag;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user