Skip to content

Commit e701801

Browse files
sjaakdgunnarmorling
authored andcommitted
mapstruct#187 introducing constant mapping
1 parent c8f6be3 commit e701801

13 files changed

Lines changed: 623 additions & 54 deletions

File tree

core/src/main/java/org/mapstruct/Mapping.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@
3535
public @interface Mapping {
3636

3737
/**
38-
* The source name of the configured property as defined by the JavaBeans specification. If used to map an enum
39-
* constant, the name of the constant member is to be given.
38+
* The source to use for this Mapping. This can either be:
39+
* <ol>
40+
* <li>The source name of the configured property as defined by the JavaBeans specification.</li>
41+
* <li>When used to map an enum constant, the name of the constant member is to be given<./li>.
42+
* </ol>
4043
*
41-
* @return The source name of the configured property or enum constant
44+
* @return The source name of the configured property or enum constant.
4245
*/
43-
String source();
46+
String source() default "";
4447

4548
/**
4649
* The target name of the configured property as defined by the JavaBeans specification. Defaults to the source name
@@ -57,4 +60,12 @@
5760
* @return A date format string as processable by {@link SimpleDateFormat}.
5861
*/
5962
String dateFormat() default "";
63+
64+
/**
65+
* {@link String} expression that uses available mappings and conversion to set the designated target property to
66+
* the provided expression.
67+
*
68+
* @return expression
69+
*/
70+
String expression() default "";
6071
}

processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,45 @@
3838
public class BeanMappingMethod extends MappingMethod {
3939

4040
private final List<PropertyMapping> propertyMappings;
41+
private final Map<String, List<PropertyMapping>> mappingsByParameter;
42+
private final List<PropertyMapping> constantMappings;
43+
44+
4145
private final FactoryMethod factoryMethod;
4246

4347
public BeanMappingMethod(SourceMethod method,
4448
List<PropertyMapping> propertyMappings,
4549
FactoryMethod factoryMethod) {
4650
super( method );
4751
this.propertyMappings = propertyMappings;
48-
this.factoryMethod = factoryMethod;
49-
}
50-
51-
public List<PropertyMapping> getPropertyMappings() {
52-
return propertyMappings;
53-
}
5452

55-
public Map<String, List<PropertyMapping>> getPropertyMappingsByParameter() {
56-
Map<String, List<PropertyMapping>> mappingsByParameter = new HashMap<String, List<PropertyMapping>>();
5753

54+
// intialize constant mappings as all mappings, but take out the ones that can be contributed to a
55+
// parameter mapping.
56+
this.mappingsByParameter = new HashMap<String, List<PropertyMapping>>();
57+
this.constantMappings = new ArrayList<PropertyMapping>( propertyMappings );
5858
for ( Parameter sourceParameter : getSourceParameters() ) {
5959
ArrayList<PropertyMapping> mappingsOfParameter = new ArrayList<PropertyMapping>();
6060
mappingsByParameter.put( sourceParameter.getName(), mappingsOfParameter );
6161
for ( PropertyMapping mapping : propertyMappings ) {
62-
if ( mapping.getSourceBeanName().equals( sourceParameter.getName() ) ) {
62+
if ( sourceParameter.getName().equals( mapping.getSourceBeanName() ) ) {
6363
mappingsOfParameter.add( mapping );
64+
constantMappings.remove( mapping );
6465
}
6566
}
6667
}
68+
this.factoryMethod = factoryMethod;
69+
}
70+
71+
public List<PropertyMapping> getPropertyMappings() {
72+
return propertyMappings;
73+
}
74+
75+
public List<PropertyMapping> getConstantMappings() {
76+
return constantMappings;
77+
}
78+
79+
public Map<String, List<PropertyMapping>> getPropertyMappingsByParameter() {
6780
return mappingsByParameter;
6881
}
6982

processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.util.HashMap;
2323
import java.util.List;
2424
import java.util.Map;
25+
import javax.annotation.processing.Messager;
2526
import javax.lang.model.element.AnnotationMirror;
2627
import javax.lang.model.element.AnnotationValue;
2728
import javax.lang.model.element.Element;
29+
import javax.tools.Diagnostic;
2830

2931
import org.mapstruct.ap.prism.MappingPrism;
3032
import org.mapstruct.ap.prism.MappingsPrism;
@@ -40,42 +42,63 @@ public class Mapping {
4042
private final String sourceName;
4143
private final String sourceParameterName;
4244
private final String sourcePropertyName;
45+
private final String expression;
4346
private final String targetName;
4447
private final String dateFormat;
4548
private final AnnotationMirror mirror;
4649
private final AnnotationValue sourceAnnotationValue;
4750
private final AnnotationValue targetAnnotationValue;
4851

49-
public static Map<String, List<Mapping>> fromMappingsPrism(MappingsPrism mappingsAnnotation, Element element) {
52+
public static Map<String, List<Mapping>> fromMappingsPrism(MappingsPrism mappingsAnnotation, Element element,
53+
Messager messager) {
5054
Map<String, List<Mapping>> mappings = new HashMap<String, List<Mapping>>();
5155

52-
for ( MappingPrism mapping : mappingsAnnotation.value() ) {
53-
if ( !mappings.containsKey( mapping.source() ) ) {
54-
mappings.put( mapping.source(), new ArrayList<Mapping>() );
56+
for ( MappingPrism mappingPrism : mappingsAnnotation.value() ) {
57+
if ( !mappings.containsKey( mappingPrism.source() ) ) {
58+
mappings.put( mappingPrism.source(), new ArrayList<Mapping>() );
59+
}
60+
Mapping mapping = fromMappingPrism( mappingPrism, element, messager );
61+
if ( mapping != null ) {
62+
mappings.get( mappingPrism.source() ).add( mapping );
5563
}
56-
mappings.get( mapping.source() ).add( fromMappingPrism( mapping, element ) );
5764
}
5865

5966
return mappings;
6067
}
6168

62-
public static Mapping fromMappingPrism(MappingPrism mapping, Element element) {
69+
public static Mapping fromMappingPrism(MappingPrism mappingPrism, Element element, Messager messager) {
6370
String[] sourceNameParts = getSourceNameParts(
64-
mapping.source(),
71+
mappingPrism.source(),
6572
element,
66-
mapping.mirror,
67-
mapping.values.source()
73+
mappingPrism.mirror,
74+
mappingPrism.values.source()
6875
);
6976

77+
if ( mappingPrism.source().isEmpty() && mappingPrism.expression().isEmpty() ) {
78+
messager.printMessage( Diagnostic.Kind.ERROR,
79+
"Either define a source or an expression in a Mapping",
80+
element
81+
);
82+
return null;
83+
}
84+
else if ( !mappingPrism.source().isEmpty() && !mappingPrism.expression().isEmpty() ) {
85+
messager.printMessage( Diagnostic.Kind.ERROR,
86+
"Source and expression are both defined in Mapping, either define a source or an expression",
87+
element
88+
);
89+
return null;
90+
}
91+
7092
return new Mapping(
71-
mapping.source(),
93+
mappingPrism.source(),
7294
sourceNameParts != null ? sourceNameParts[0] : null,
73-
sourceNameParts != null ? sourceNameParts[1] : mapping.source(),
74-
mapping.target(),
75-
mapping.dateFormat(),
76-
mapping.mirror,
77-
mapping.values.source(),
78-
mapping.values.target()
95+
sourceNameParts != null ? sourceNameParts[1] : mappingPrism.source(),
96+
mappingPrism.expression(),
97+
mappingPrism.target(),
98+
mappingPrism.dateFormat(),
99+
mappingPrism.mirror,
100+
mappingPrism.values.source(),
101+
mappingPrism.values.target()
79102
);
80103
}
81104

@@ -98,12 +121,13 @@ private static String[] getSourceNameParts(String sourceName, Element element, A
98121
return parts;
99122
}
100123

101-
private Mapping(String sourceName, String sourceParameterName, String sourcePropertyName, String targetName,
102-
String dateFormat, AnnotationMirror mirror, AnnotationValue sourceAnnotationValue,
103-
AnnotationValue targetAnnotationValue) {
124+
private Mapping(String sourceName, String sourceParameterName, String sourcePropertyName, String expression,
125+
String targetName, String dateFormat, AnnotationMirror mirror,
126+
AnnotationValue sourceAnnotationValue, AnnotationValue targetAnnotationValue) {
104127
this.sourceName = sourceName;
105128
this.sourceParameterName = sourceParameterName;
106129
this.sourcePropertyName = sourcePropertyName;
130+
this.expression = expression;
107131
this.targetName = targetName.equals( "" ) ? sourceName : targetName;
108132
this.dateFormat = dateFormat;
109133
this.mirror = mirror;
@@ -139,6 +163,11 @@ public String getSourceParameterName() {
139163
return sourceParameterName;
140164
}
141165

166+
public String getExpression() {
167+
return expression;
168+
}
169+
170+
142171
public String getTargetName() {
143172
return targetName;
144173
}
@@ -160,16 +189,22 @@ public AnnotationValue getTargetAnnotationValue() {
160189
}
161190

162191
public Mapping reverse() {
163-
return new Mapping(
164-
targetName,
165-
null,
166-
targetName,
167-
sourceName,
168-
dateFormat,
169-
mirror,
170-
sourceAnnotationValue,
171-
targetAnnotationValue
172-
);
192+
Mapping reverse = null;
193+
if ( expression != null ) {
194+
/* mapping can only be reversed if the source was not a constant */
195+
reverse = new Mapping(
196+
targetName,
197+
null,
198+
targetName,
199+
expression,
200+
sourceName,
201+
dateFormat,
202+
mirror,
203+
sourceAnnotationValue,
204+
targetAnnotationValue
205+
);
206+
}
207+
return reverse;
173208
}
174209

175210
@Override

0 commit comments

Comments
 (0)