mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#304 Allowing to configure dependencies between properties via @Mapping#dependsOn()
This commit is contained in:
parent
9b888847ea
commit
2d7ab089ff
@ -137,10 +137,21 @@ public @interface Mapping {
|
||||
*/
|
||||
Class<? extends Annotation>[] qualifiedBy() default { };
|
||||
|
||||
/**
|
||||
/**
|
||||
* Specifies the result type of the mapping method to be used in case multiple mapping methods qualify.
|
||||
*
|
||||
* @return the resultType to select
|
||||
*/
|
||||
Class<?> resultType() default void.class;
|
||||
|
||||
/**
|
||||
* One or more properties of the result type on which the mapped property depends. The generated method
|
||||
* implementation will invoke the setters of the result type ordered so that the given dependency relationship(s)
|
||||
* are satisfied. Useful in case one property setter depends on the state of another property of the result type.
|
||||
* <p>
|
||||
* An error will be raised in case a cycle in the dependency relationships is detected.
|
||||
*
|
||||
* @return the dependencies of the mapped property
|
||||
*/
|
||||
String[] dependsOn() default { };
|
||||
}
|
||||
|
@ -141,4 +141,15 @@ public @interface Mapping {
|
||||
* @return the resultType to select
|
||||
*/
|
||||
Class<?> resultType() default void.class;
|
||||
|
||||
/**
|
||||
* One or more properties of the result type on which the mapped property depends. The generated method
|
||||
* implementation will invoke the setters of the result type ordered so that the given dependency relationship(s)
|
||||
* are satisfied. Useful in case one property setter depends on the state of another property of the result type.
|
||||
* <p>
|
||||
* An error will be raised in case a cycle in the dependency relationships is detected.
|
||||
*
|
||||
* @return the dependencies of the mapped property
|
||||
*/
|
||||
String[] dependsOn() default { };
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ package org.mapstruct.ap.model;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@ -38,6 +40,7 @@ import org.mapstruct.ap.model.PropertyMapping.JavaExpressionMappingBuilder;
|
||||
import org.mapstruct.ap.model.PropertyMapping.PropertyMappingBuilder;
|
||||
import org.mapstruct.ap.model.common.Parameter;
|
||||
import org.mapstruct.ap.model.common.Type;
|
||||
import org.mapstruct.ap.model.dependency.GraphAnalyzer;
|
||||
import org.mapstruct.ap.model.source.Mapping;
|
||||
import org.mapstruct.ap.model.source.SourceMethod;
|
||||
import org.mapstruct.ap.model.source.SourceReference;
|
||||
@ -146,11 +149,14 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
if ( !resultType.isAssignableTo( method.getResultType() ) ) {
|
||||
ctx.getMessager().printMessage( method.getExecutable(),
|
||||
beanMappingPrism.mirror,
|
||||
Message.BEANMAPPING_NOT_ASSIGNABLE, resultType, method.getResultType());
|
||||
Message.BEANMAPPING_NOT_ASSIGNABLE, resultType, method.getResultType()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortPropertyMappingsByDependencies();
|
||||
|
||||
return new BeanMappingMethod(
|
||||
method,
|
||||
propertyMappings,
|
||||
@ -161,6 +167,34 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
);
|
||||
}
|
||||
|
||||
private void sortPropertyMappingsByDependencies() {
|
||||
final GraphAnalyzer graphAnalyzer = new GraphAnalyzer();
|
||||
|
||||
for ( PropertyMapping propertyMapping : propertyMappings ) {
|
||||
graphAnalyzer.addNode( propertyMapping.getName(), propertyMapping.getDependsOn() );
|
||||
}
|
||||
|
||||
graphAnalyzer.analyze();
|
||||
|
||||
Collections.sort(
|
||||
propertyMappings, new Comparator<PropertyMapping>() {
|
||||
|
||||
@Override
|
||||
public int compare(PropertyMapping o1, PropertyMapping o2) {
|
||||
if ( graphAnalyzer.getAllDescendants( o1.getName() ).contains( o2.getName() ) ) {
|
||||
return 1;
|
||||
}
|
||||
else if ( graphAnalyzer.getAllDescendants( o2.getName() ).contains( o1.getName() ) ) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all defined mapping methods ({@code @Mapping(s)}), either directly given or inherited from the
|
||||
* inverse mapping method.
|
||||
@ -221,6 +255,7 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
.resultType( mapping.getResultType() )
|
||||
.dateFormat( mapping.getDateFormat() )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( mapping.getDependsOn() )
|
||||
.build();
|
||||
handledTargets.add( mapping.getTargetName() );
|
||||
unprocessedSourceParameters.remove( sourceRef.getParameter() );
|
||||
@ -239,10 +274,12 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
.sourceMethod( method )
|
||||
.constantExpression( "\"" + mapping.getConstant() + "\"" )
|
||||
.targetAccessor( targetProperty )
|
||||
.targetPropertyName( mapping.getTargetName() )
|
||||
.dateFormat( mapping.getDateFormat() )
|
||||
.qualifiers( mapping.getQualifiers() )
|
||||
.resultType( mapping.getResultType() )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( mapping.getDependsOn() )
|
||||
.build();
|
||||
handledTargets.add( mapping.getTargetName() );
|
||||
}
|
||||
@ -256,6 +293,8 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
.javaExpression( mapping.getJavaExpression() )
|
||||
.targetAccessor( targetProperty )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.targetPropertyName( mapping.getTargetName() )
|
||||
.dependsOn( mapping.getDependsOn() )
|
||||
.build();
|
||||
handledTargets.add( mapping.getTargetName() );
|
||||
}
|
||||
@ -333,6 +372,7 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
.resultType( mapping != null ? mapping.getResultType() : null )
|
||||
.dateFormat( mapping != null ? mapping.getDateFormat() : null )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( mapping != null ? mapping.getDependsOn() : Collections.<String>emptyList() )
|
||||
.build();
|
||||
|
||||
unprocessedSourceParameters.remove( sourceParameter );
|
||||
@ -394,6 +434,7 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
.resultType( mapping != null ? mapping.getResultType() : null )
|
||||
.dateFormat( mapping != null ? mapping.getDateFormat() : null )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( mapping != null ? mapping.getDependsOn() : Collections.<String>emptyList() )
|
||||
.build();
|
||||
|
||||
propertyMappings.add( propertyMapping );
|
||||
|
@ -20,8 +20,10 @@ package org.mapstruct.ap.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
@ -31,8 +33,8 @@ import org.mapstruct.ap.model.assignment.Assignment;
|
||||
import org.mapstruct.ap.model.assignment.GetterWrapperForCollectionsAndMaps;
|
||||
import org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper;
|
||||
import org.mapstruct.ap.model.assignment.NullCheckWrapper;
|
||||
import org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps;
|
||||
import org.mapstruct.ap.model.assignment.SetterWrapper;
|
||||
import org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps;
|
||||
import org.mapstruct.ap.model.common.ModelElement;
|
||||
import org.mapstruct.ap.model.common.Parameter;
|
||||
import org.mapstruct.ap.model.common.Type;
|
||||
@ -41,12 +43,12 @@ import org.mapstruct.ap.model.source.SourceMethod;
|
||||
import org.mapstruct.ap.model.source.SourceReference;
|
||||
import org.mapstruct.ap.model.source.SourceReference.PropertyEntry;
|
||||
import org.mapstruct.ap.util.Executables;
|
||||
import org.mapstruct.ap.util.Message;
|
||||
import org.mapstruct.ap.util.Strings;
|
||||
|
||||
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.DIRECT;
|
||||
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED;
|
||||
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED_MAPPED;
|
||||
import org.mapstruct.ap.util.Message;
|
||||
|
||||
/**
|
||||
* Represents the mapping between a source and target property, e.g. from {@code String Source#foo} to
|
||||
@ -57,10 +59,12 @@ import org.mapstruct.ap.util.Message;
|
||||
*/
|
||||
public class PropertyMapping extends ModelElement {
|
||||
|
||||
private final String name;
|
||||
private final String sourceBeanName;
|
||||
private final String targetAccessorName;
|
||||
private final Type targetType;
|
||||
private final Assignment assignment;
|
||||
private final List<String> dependsOn;
|
||||
|
||||
public static class PropertyMappingBuilder {
|
||||
|
||||
@ -74,6 +78,7 @@ public class PropertyMapping extends ModelElement {
|
||||
private TypeMirror resultType;
|
||||
private SourceReference sourceReference;
|
||||
private Collection<String> existingVariableNames;
|
||||
private List<String> dependsOn;
|
||||
|
||||
public PropertyMappingBuilder mappingContext(MappingBuilderContext mappingContext) {
|
||||
this.ctx = mappingContext;
|
||||
@ -120,6 +125,11 @@ public class PropertyMapping extends ModelElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyMappingBuilder dependsOn(List<String> dependsOn) {
|
||||
this.dependsOn = dependsOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
private enum TargetAccessorType {
|
||||
|
||||
GETTER,
|
||||
@ -195,10 +205,12 @@ public class PropertyMapping extends ModelElement {
|
||||
}
|
||||
|
||||
return new PropertyMapping(
|
||||
targetPropertyName,
|
||||
sourceReference.getParameter().getName(),
|
||||
targetAccessor.getSimpleName().toString(),
|
||||
targetType,
|
||||
assignment
|
||||
assignment,
|
||||
dependsOn
|
||||
);
|
||||
}
|
||||
|
||||
@ -465,10 +477,12 @@ public class PropertyMapping extends ModelElement {
|
||||
private SourceMethod method;
|
||||
private String constantExpression;
|
||||
private ExecutableElement targetAccessor;
|
||||
private String targetPropertyName;
|
||||
private String dateFormat;
|
||||
private List<TypeMirror> qualifiers;
|
||||
private TypeMirror resultType;
|
||||
private Collection<String> existingVariableNames;
|
||||
private List<String> dependsOn;
|
||||
|
||||
public ConstantMappingBuilder mappingContext(MappingBuilderContext mappingContext) {
|
||||
this.ctx = mappingContext;
|
||||
@ -490,6 +504,11 @@ public class PropertyMapping extends ModelElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConstantMappingBuilder targetPropertyName(String targetPropertyName) {
|
||||
this.targetPropertyName = targetPropertyName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConstantMappingBuilder dateFormat(String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
return this;
|
||||
@ -510,6 +529,11 @@ public class PropertyMapping extends ModelElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConstantMappingBuilder dependsOn(List<String> dependsOn) {
|
||||
this.dependsOn = dependsOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyMapping build() {
|
||||
|
||||
// source
|
||||
@ -525,8 +549,6 @@ public class PropertyMapping extends ModelElement {
|
||||
targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
|
||||
}
|
||||
|
||||
String targetPropertyName = Executables.getPropertyName( targetAccessor );
|
||||
|
||||
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
|
||||
method,
|
||||
mappedElement,
|
||||
@ -565,7 +587,13 @@ public class PropertyMapping extends ModelElement {
|
||||
);
|
||||
}
|
||||
|
||||
return new PropertyMapping( targetAccessor.getSimpleName().toString(), targetType, assignment );
|
||||
return new PropertyMapping(
|
||||
targetPropertyName,
|
||||
targetAccessor.getSimpleName().toString(),
|
||||
targetType,
|
||||
assignment,
|
||||
dependsOn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,6 +604,8 @@ public class PropertyMapping extends ModelElement {
|
||||
private String javaExpression;
|
||||
private ExecutableElement targetAccessor;
|
||||
private Collection<String> existingVariableNames;
|
||||
private String targetPropertyName;
|
||||
private List<String> dependsOn;
|
||||
|
||||
public JavaExpressionMappingBuilder mappingContext(MappingBuilderContext mappingContext) {
|
||||
this.ctx = mappingContext;
|
||||
@ -602,6 +632,16 @@ public class PropertyMapping extends ModelElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
public JavaExpressionMappingBuilder targetPropertyName(String targetPropertyName) {
|
||||
this.targetPropertyName = targetPropertyName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JavaExpressionMappingBuilder dependsOn(List<String> dependsOn) {
|
||||
this.dependsOn = dependsOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PropertyMapping build() {
|
||||
|
||||
Assignment assignment = AssignmentFactory.createDirect( javaExpression );
|
||||
@ -623,24 +663,38 @@ public class PropertyMapping extends ModelElement {
|
||||
);
|
||||
}
|
||||
|
||||
return new PropertyMapping( targetAccessor.getSimpleName().toString(), targetType, assignment );
|
||||
return new PropertyMapping(
|
||||
targetPropertyName,
|
||||
targetAccessor.getSimpleName().toString(),
|
||||
targetType,
|
||||
assignment,
|
||||
dependsOn
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Constructor for creating mappings of constant expressions.
|
||||
private PropertyMapping(String targetAccessorName, Type targetType, Assignment propertyAssignment) {
|
||||
this( null, targetAccessorName, targetType, propertyAssignment );
|
||||
private PropertyMapping(String name, String targetAccessorName, Type targetType, Assignment propertyAssignment,
|
||||
List<String> dependsOn) {
|
||||
this( name, null, targetAccessorName, targetType, propertyAssignment, dependsOn );
|
||||
}
|
||||
|
||||
private PropertyMapping(String sourceBeanName, String targetAccessorName, Type targetType, Assignment assignment) {
|
||||
|
||||
private PropertyMapping(String name, String sourceBeanName, String targetAccessorName, Type targetType,
|
||||
Assignment assignment, List<String> dependsOn) {
|
||||
this.name = name;
|
||||
this.sourceBeanName = sourceBeanName;
|
||||
|
||||
this.targetAccessorName = targetAccessorName;
|
||||
this.targetType = targetType;
|
||||
|
||||
this.assignment = assignment;
|
||||
this.dependsOn = dependsOn != null ? dependsOn : Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this mapping (property name on the target side)
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSourceBeanName() {
|
||||
@ -664,12 +718,17 @@ public class PropertyMapping extends ModelElement {
|
||||
return assignment.getImportTypes();
|
||||
}
|
||||
|
||||
public List<String> getDependsOn() {
|
||||
return dependsOn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PropertyMapping {"
|
||||
+ "\n targetName='" + targetAccessorName + "\',"
|
||||
+ "\n name='" + name + "\',"
|
||||
+ "\n targetType=" + targetType + ","
|
||||
+ "\n propertyAssignment=" + assignment
|
||||
+ "\n propertyAssignment=" + assignment + ","
|
||||
+ "\n dependsOn=" + dependsOn
|
||||
+ "\n}";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.dependency;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Analyzes graphs: Discovers all descendants of given nodes and detects cyclic dependencies between nodes if present.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public class GraphAnalyzer {
|
||||
|
||||
private final Map<String, Node> nodes = new HashMap<String, Node>();
|
||||
private final Set<List<String>> cycles = new HashSet<List<String>>();
|
||||
|
||||
private final Stack<Node> currentPath = new Stack<Node>();
|
||||
|
||||
public void addNode(String name, List<String> descendants) {
|
||||
Node node = getNode( name );
|
||||
|
||||
for ( String descendant : descendants ) {
|
||||
node.addDescendant( getNode( descendant ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void addNode(String name, String... descendants) {
|
||||
Node node = getNode( name );
|
||||
|
||||
for ( String descendant : descendants ) {
|
||||
node.addDescendant( getNode( descendant ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a full traversal of the graph, detecting potential cycles and calculates the full list of descendants of
|
||||
* the nodes.
|
||||
*/
|
||||
public void analyze() {
|
||||
for ( Node node : nodes.values() ) {
|
||||
depthFirstSearch( node );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the descendants of the given node, either direct or transitive ones.
|
||||
* <p>
|
||||
* <b>Note</b>:The list will only be complete if the graph contains no cycles.
|
||||
*/
|
||||
public Set<String> getAllDescendants(String name) {
|
||||
Node node = nodes.get( name );
|
||||
return node != null ? node.getAllDescendants() : Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
public Set<List<String>> getCycles() {
|
||||
return cycles;
|
||||
}
|
||||
|
||||
private void depthFirstSearch(Node node) {
|
||||
if ( node.isProcessed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentPath.push( node );
|
||||
|
||||
// the node is on the stack already -> cycle
|
||||
if ( node.isVisited() ) {
|
||||
cycles.add( getCurrentCycle( node ) );
|
||||
currentPath.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
node.setVisited( true );
|
||||
|
||||
for ( Node descendant : node.getDescendants() ) {
|
||||
depthFirstSearch( descendant );
|
||||
node.getAllDescendants().addAll( descendant.getAllDescendants() );
|
||||
}
|
||||
|
||||
node.setProcessed( true );
|
||||
currentPath.pop();
|
||||
}
|
||||
|
||||
private List<String> getCurrentCycle(Node start) {
|
||||
List<String> cycle = new ArrayList<String>();
|
||||
boolean inCycle = false;
|
||||
|
||||
for ( Node n : currentPath ) {
|
||||
if ( n.getName().equals( start.getName() ) ) {
|
||||
inCycle = true;
|
||||
}
|
||||
|
||||
if ( inCycle ) {
|
||||
cycle.add( n.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
return cycle;
|
||||
}
|
||||
|
||||
private Node getNode(String name) {
|
||||
Node node = nodes.get( name );
|
||||
|
||||
if ( node == null ) {
|
||||
node = new Node( name );
|
||||
nodes.put( name, node );
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.dependency;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A node of a directed graph.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
class Node {
|
||||
|
||||
private final String name;
|
||||
private boolean visited;
|
||||
private boolean processed;
|
||||
|
||||
/**
|
||||
* The direct descendants of this node.
|
||||
*/
|
||||
private final List<Node> descendants;
|
||||
|
||||
/**
|
||||
* All descendants of this node, direct and transitive ones, as discovered through graph traversal.
|
||||
*/
|
||||
private final Set<String> allDescendants;
|
||||
|
||||
public Node(String name) {
|
||||
this.name = name;
|
||||
descendants = new ArrayList<Node>();
|
||||
allDescendants = new HashSet<String>();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isVisited() {
|
||||
return visited;
|
||||
}
|
||||
|
||||
public void setVisited(boolean visited) {
|
||||
this.visited = visited;
|
||||
}
|
||||
|
||||
public boolean isProcessed() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
public void setProcessed(boolean processed) {
|
||||
this.processed = processed;
|
||||
}
|
||||
|
||||
public void addDescendant(Node node) {
|
||||
descendants.add( node );
|
||||
allDescendants.add( node.getName() );
|
||||
}
|
||||
|
||||
public List<Node> getDescendants() {
|
||||
return descendants;
|
||||
}
|
||||
|
||||
public Set<String> getAllDescendants() {
|
||||
return allDescendants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if ( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
Node other = (Node) obj;
|
||||
if ( name == null ) {
|
||||
if ( other.name != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( !name.equals( other.name ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -19,12 +19,12 @@
|
||||
package org.mapstruct.ap.model.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
@ -57,6 +57,7 @@ public class Mapping {
|
||||
private final List<TypeMirror> qualifiers;
|
||||
private final TypeMirror resultType;
|
||||
private final boolean isIgnored;
|
||||
private final List<String> dependsOn;
|
||||
|
||||
private final AnnotationMirror mirror;
|
||||
private final AnnotationValue sourceAnnotationValue;
|
||||
@ -120,6 +121,8 @@ public class Mapping {
|
||||
|
||||
boolean resultTypeIsDefined = !TypeKind.VOID.equals( mappingPrism.resultType().getKind() );
|
||||
TypeMirror resultType = resultTypeIsDefined ? mappingPrism.resultType() : null;
|
||||
List<String> dependsOn =
|
||||
mappingPrism.dependsOn() != null ? mappingPrism.dependsOn() : Collections.<String>emptyList();
|
||||
|
||||
return new Mapping(
|
||||
source,
|
||||
@ -132,7 +135,8 @@ public class Mapping {
|
||||
mappingPrism.mirror,
|
||||
mappingPrism.values.source(),
|
||||
mappingPrism.values.target(),
|
||||
resultType
|
||||
resultType,
|
||||
dependsOn
|
||||
);
|
||||
}
|
||||
|
||||
@ -141,7 +145,7 @@ public class Mapping {
|
||||
String dateFormat, List<TypeMirror> qualifiers,
|
||||
boolean isIgnored, AnnotationMirror mirror,
|
||||
AnnotationValue sourceAnnotationValue, AnnotationValue targetAnnotationValue,
|
||||
TypeMirror resultType ) {
|
||||
TypeMirror resultType, List<String> dependsOn) {
|
||||
this.sourceName = sourceName;
|
||||
this.constant = constant;
|
||||
this.javaExpression = javaExpression;
|
||||
@ -153,6 +157,7 @@ public class Mapping {
|
||||
this.sourceAnnotationValue = sourceAnnotationValue;
|
||||
this.targetAnnotationValue = targetAnnotationValue;
|
||||
this.resultType = resultType;
|
||||
this.dependsOn = dependsOn;
|
||||
}
|
||||
|
||||
private static String getExpression(MappingPrism mappingPrism, ExecutableElement element,
|
||||
@ -243,6 +248,10 @@ public class Mapping {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
public List<String> getDependsOn() {
|
||||
return dependsOn;
|
||||
}
|
||||
|
||||
private boolean hasPropertyInReverseMethod(String name, SourceMethod method) {
|
||||
CollectionMappingStrategyPrism cms = method.getMapperConfiguration().getCollectionMappingStrategy();
|
||||
return method.getResultType().getTargetAccessors( cms ).containsKey( name );
|
||||
@ -287,7 +296,8 @@ public class Mapping {
|
||||
mirror,
|
||||
sourceAnnotationValue,
|
||||
targetAnnotationValue,
|
||||
null
|
||||
null,
|
||||
Collections.<String>emptyList()
|
||||
);
|
||||
|
||||
reverse.init( method, messager, typeFactory );
|
||||
@ -311,8 +321,9 @@ public class Mapping {
|
||||
mirror,
|
||||
sourceAnnotationValue,
|
||||
targetAnnotationValue,
|
||||
resultType
|
||||
);
|
||||
resultType,
|
||||
dependsOn
|
||||
);
|
||||
|
||||
if ( sourceReference != null ) {
|
||||
mapping.sourceReference = sourceReference.copyForInheritanceTo( method );
|
||||
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
public class Address {
|
||||
|
||||
private String firstName;
|
||||
private String middleName;
|
||||
private String lastName;
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
public class AddressDto {
|
||||
|
||||
private String givenName;
|
||||
private String middleName;
|
||||
private String surName;
|
||||
private String fullName;
|
||||
|
||||
public String getGivenName() {
|
||||
return givenName;
|
||||
}
|
||||
|
||||
public void setGivenName(String givenName) {
|
||||
this.givenName = givenName;
|
||||
this.fullName = givenName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
this.fullName += " " + middleName;
|
||||
}
|
||||
|
||||
public String getSurName() {
|
||||
return surName;
|
||||
}
|
||||
|
||||
public void setSurName(String surName) {
|
||||
this.surName = surName;
|
||||
this.fullName += " " + surName;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface AddressMapper {
|
||||
|
||||
AddressMapper INSTANCE = Mappers.getMapper( AddressMapper.class );
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "surName", source = "lastName", dependsOn = "middleName"),
|
||||
@Mapping(target = "middleName", dependsOn = "givenName"),
|
||||
@Mapping(target = "givenName", source = "firstName")
|
||||
})
|
||||
AddressDto addressToDto(Address address);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "lastName", dependsOn = { "firstName", "middleName" })
|
||||
})
|
||||
PersonDto personToDto(Person person);
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mapstruct.ap.model.dependency.GraphAnalyzer;
|
||||
import org.mapstruct.ap.util.Strings;
|
||||
|
||||
/**
|
||||
* Unit test for {@link GraphAnalyzer}.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public class GraphAnalyzerTest {
|
||||
|
||||
private GraphAnalyzer detector;
|
||||
|
||||
@Before
|
||||
public void setUpDetector() {
|
||||
detector = new GraphAnalyzer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyGraph() {
|
||||
detector.analyze();
|
||||
|
||||
assertThat( detector.getCycles() ).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleNode() {
|
||||
detector.addNode( "a" );
|
||||
detector.analyze();
|
||||
|
||||
assertThat( detector.getCycles() ).isEmpty();
|
||||
assertThat( detector.getAllDescendants( "a" ) ).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoNodesWithoutCycle() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( detector.getCycles() ).isEmpty();
|
||||
assertThat( detector.getAllDescendants( "a" ) ).containsOnly( "b" );
|
||||
assertThat( detector.getAllDescendants( "b" ) ).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoNodesWithCycle() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b", "a" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).containsOnly( "a -> b -> a" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeNodesWithCycleBetweenTwo() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b", "a", "c" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).containsOnly( "a -> b -> a" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoNodesWithSharedDescendantWithoutCycle() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b", "c" );
|
||||
detector.addNode( "a", "c" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).isEmpty();
|
||||
assertThat( detector.getAllDescendants( "a" ) ).containsOnly( "b", "c" );
|
||||
assertThat( detector.getAllDescendants( "b" ) ).containsOnly( "c" );
|
||||
assertThat( detector.getAllDescendants( "c" ) ).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeNodesWithoutCycle() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "c", "b" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).isEmpty();
|
||||
|
||||
assertThat( detector.getAllDescendants( "a" ) ).containsOnly( "b" );
|
||||
assertThat( detector.getAllDescendants( "b" ) ).isEmpty();
|
||||
assertThat( detector.getAllDescendants( "c" ) ).containsOnly( "b" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourNodesWithCycleBetweenThree() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b", "c" );
|
||||
detector.addNode( "c", "d" );
|
||||
detector.addNode( "d", "b" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).containsOnly( "b -> c -> d -> b" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourNodesWithTwoCycles() {
|
||||
detector.addNode( "a", "b" );
|
||||
detector.addNode( "b", "a" );
|
||||
detector.addNode( "c", "d" );
|
||||
detector.addNode( "d", "c" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).containsOnly( "a -> b -> a", "c -> d -> c" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourNodesWithoutCycle() {
|
||||
detector.addNode( "a", "b1" );
|
||||
detector.addNode( "a", "b2" );
|
||||
detector.addNode( "b1", "c" );
|
||||
detector.addNode( "b2", "c" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).isEmpty();
|
||||
assertThat( detector.getAllDescendants( "a" ) ).containsOnly( "b1", "b2", "c" );
|
||||
assertThat( detector.getAllDescendants( "b1" ) ).containsOnly( "c" );
|
||||
assertThat( detector.getAllDescendants( "b2" ) ).containsOnly( "c" );
|
||||
assertThat( detector.getAllDescendants( "c" ) ).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourNodesWithCycle() {
|
||||
detector.addNode( "a", "b1" );
|
||||
detector.addNode( "a", "b2" );
|
||||
detector.addNode( "b1", "c" );
|
||||
detector.addNode( "b2", "c" );
|
||||
detector.addNode( "c", "a" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( asStrings( detector.getCycles() ) ).containsOnly( "a -> b1 -> c -> a", "a -> b2 -> c -> a" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eightNodesWithoutCycle() {
|
||||
detector.addNode( "a", "b1" );
|
||||
detector.addNode( "a", "b2" );
|
||||
detector.addNode( "b1", "c1" );
|
||||
detector.addNode( "b1", "c2" );
|
||||
detector.addNode( "b2", "c3" );
|
||||
detector.addNode( "b2", "c4" );
|
||||
|
||||
detector.analyze();
|
||||
|
||||
assertThat( detector.getCycles() ).isEmpty();
|
||||
|
||||
assertThat( detector.getAllDescendants( "a" ) ).containsOnly( "b1", "b2", "c1", "c2", "c3", "c4" );
|
||||
assertThat( detector.getAllDescendants( "b1" ) ).containsOnly( "c1", "c2" );
|
||||
assertThat( detector.getAllDescendants( "b2" ) ).containsOnly( "c3", "c4" );
|
||||
}
|
||||
|
||||
private Set<String> asStrings(Set<List<String>> cycles) {
|
||||
Set<String> asStrings = new HashSet<String>();
|
||||
|
||||
for ( List<String> cycle : cycles ) {
|
||||
asStrings.add( asString( cycle ) );
|
||||
}
|
||||
|
||||
return asStrings;
|
||||
}
|
||||
|
||||
private String asString(List<String> cycle) {
|
||||
return Strings.join( normalize( cycle ), " -> " );
|
||||
}
|
||||
|
||||
/**
|
||||
* "Normalizes" a cycle so that the minimum element comes first. E.g. both the cycles {@code b -> c -> a -> b} and
|
||||
* {@code c -> a -> b -> c} would be normalized to {@code a -> b -> c -> a}.
|
||||
*/
|
||||
private List<String> normalize(List<String> cycle) {
|
||||
// remove the first element
|
||||
cycle = cycle.subList( 1, cycle.size() );
|
||||
|
||||
// rotate the cycle so the minimum element comes first
|
||||
Collections.rotate( cycle, -cycle.indexOf( Collections.min( cycle ) ) );
|
||||
|
||||
// add the first element add the end to re-close the cycle
|
||||
cycle.add( cycle.get( 0 ) );
|
||||
|
||||
return cycle;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for ordering mapped attributes by means of {@link Mapping#dependsOn()}.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
@WithClasses({ Person.class, PersonDto.class, Address.class, AddressDto.class, AddressMapper.class })
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
public class OrderingTest {
|
||||
|
||||
@Test
|
||||
@IssueKey("304")
|
||||
public void shouldApplyChainOfDependencies() {
|
||||
Address source = new Address();
|
||||
source.setFirstName( "Bob" );
|
||||
source.setMiddleName( "J." );
|
||||
source.setLastName( "McRobb" );
|
||||
|
||||
AddressDto target = AddressMapper.INSTANCE.addressToDto( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFullName() ).isEqualTo( "Bob J. McRobb" );
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("304")
|
||||
public void shouldApplySeveralDependenciesConfiguredForOneProperty() {
|
||||
Person source = new Person();
|
||||
source.setFirstName( "Bob" );
|
||||
source.setMiddleName( "J." );
|
||||
source.setLastName( "McRobb" );
|
||||
|
||||
PersonDto target = AddressMapper.INSTANCE.personToDto( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFullName() ).isEqualTo( "Bob J. McRobb" );
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
public class Person {
|
||||
|
||||
private String firstName;
|
||||
private String middleName;
|
||||
private String lastName;
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.dependency;
|
||||
|
||||
public class PersonDto {
|
||||
|
||||
private String firstName;
|
||||
private String middleName;
|
||||
private String lastName;
|
||||
private String fullName;
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
this.fullName = firstName + " " + middleName + " " + lastName;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user