1 /*
2  * Copyright 2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.modelmapper.internal;
17
18 import java.util.List;
19
20 import org.modelmapper.Condition;
21 import org.modelmapper.Provider;
22 import org.modelmapper.config.Configuration;
23 import org.modelmapper.convention.MatchingStrategies;
24 import org.modelmapper.convention.NameTokenizers;
25 import org.modelmapper.convention.NameTransformers;
26 import org.modelmapper.convention.NamingConventions;
27 import org.modelmapper.internal.converter.AssignableConverter;
28 import org.modelmapper.internal.converter.ConverterStore;
29 import org.modelmapper.internal.converter.MergingCollectionConverter;
30 import org.modelmapper.internal.converter.NonMergingCollectionConverter;
31 import org.modelmapper.internal.util.Assert;
32 import org.modelmapper.internal.valueaccess.ValueAccessStore;
33 import org.modelmapper.internal.valuemutate.ValueMutateStore;
34 import org.modelmapper.spi.ConditionalConverter;
35 import org.modelmapper.spi.MatchingStrategy;
36 import org.modelmapper.spi.NameTokenizer;
37 import org.modelmapper.spi.NameTransformer;
38 import org.modelmapper.spi.NamingConvention;
39 import org.modelmapper.spi.ValueReader;
40 import org.modelmapper.spi.ValueWriter;
41
42 /**
43  * Inheritable mapping configuration implementation.
44  *
45  * @author Jonathan Halterman
46  */

47 public class InheritingConfiguration implements Configuration {
48   private final Configuration parent;
49   public final TypeMapStore typeMapStore;
50   public final ConverterStore converterStore;
51   public final ValueAccessStore valueAccessStore;
52   public final ValueMutateStore valueMutateStore;
53   private NameTokenizer destinationNameTokenizer;
54   private NameTransformer destinationNameTransformer;
55   private NamingConvention destinationNamingConvention;
56   private AccessLevel fieldAccessLevel;
57   private MatchingStrategy matchingStrategy;
58   private AccessLevel methodAccessLevel;
59   private Provider<?> provider;
60   private Condition<?, ?> propertyCondition;
61   private NameTokenizer sourceNameTokenizer;
62   private NameTransformer sourceNameTransformer;
63   private NamingConvention sourceNamingConvention;
64   private Boolean fieldMatchingEnabled;
65   private Boolean ambiguityIgnored;
66   private Boolean fullTypeMatchingRequired;
67   private Boolean implicitMatchingEnabled;
68   private Boolean preferNestedProperties;
69   private Boolean skipNullEnabled;
70   private Boolean collectionsMergeEnabled;
71   private Boolean useOSGiClassLoaderBridging;
72
73   /**
74    * Creates an initial InheritingConfiguration.
75    */

76   public InheritingConfiguration() {
77     parent = null;
78     typeMapStore = new TypeMapStore(this);
79     converterStore = new ConverterStore();
80     valueAccessStore = new ValueAccessStore();
81     valueMutateStore = new ValueMutateStore();
82     sourceNameTokenizer = NameTokenizers.CAMEL_CASE;
83     destinationNameTokenizer = NameTokenizers.CAMEL_CASE;
84     sourceNamingConvention = NamingConventions.JAVABEANS_ACCESSOR;
85     destinationNamingConvention = NamingConventions.JAVABEANS_MUTATOR;
86     sourceNameTransformer = NameTransformers.JAVABEANS_ACCESSOR;
87     destinationNameTransformer = NameTransformers.JAVABEANS_MUTATOR;
88     matchingStrategy = MatchingStrategies.STANDARD;
89     fieldAccessLevel = AccessLevel.PUBLIC;
90     methodAccessLevel = AccessLevel.PUBLIC;
91     fieldMatchingEnabled = Boolean.FALSE;
92     ambiguityIgnored = Boolean.FALSE;
93     fullTypeMatchingRequired = Boolean.FALSE;
94     implicitMatchingEnabled = Boolean.TRUE;
95     preferNestedProperties = Boolean.TRUE;
96     skipNullEnabled = Boolean.FALSE;
97     useOSGiClassLoaderBridging = Boolean.FALSE;
98     collectionsMergeEnabled = Boolean.FALSE;
99   }
100
101   /**
102    * Creates a new InheritingConfiguration from the {@code source} configuration.
103    */

104   InheritingConfiguration(InheritingConfiguration source, boolean inherit) {
105     // Stores are not inheritable
106     typeMapStore = source.typeMapStore;
107     converterStore = source.converterStore;
108     valueAccessStore = source.valueAccessStore;
109     valueMutateStore = source.valueMutateStore;
110
111     if (inherit) {
112       this.parent = source;
113     } else {
114       parent = null;
115       sourceNameTokenizer = source.sourceNameTokenizer;
116       destinationNameTokenizer = source.destinationNameTokenizer;
117       sourceNamingConvention = source.sourceNamingConvention;
118       destinationNamingConvention = source.destinationNamingConvention;
119       sourceNameTransformer = source.sourceNameTransformer;
120       destinationNameTransformer = source.destinationNameTransformer;
121       matchingStrategy = source.matchingStrategy;
122       fieldAccessLevel = source.fieldAccessLevel;
123       methodAccessLevel = source.methodAccessLevel;
124       fieldMatchingEnabled = source.fieldMatchingEnabled;
125       ambiguityIgnored = source.ambiguityIgnored;
126       provider = source.provider;
127       propertyCondition = source.propertyCondition;
128       fullTypeMatchingRequired = source.fullTypeMatchingRequired;
129       implicitMatchingEnabled = source.implicitMatchingEnabled;
130       preferNestedProperties = source.preferNestedProperties;
131       skipNullEnabled = source.skipNullEnabled;
132       collectionsMergeEnabled = source.collectionsMergeEnabled;
133     }
134   }
135
136   @Override
137   public <T> Configuration addValueReader(ValueReader<T> valueReader) {
138     getValueReaders().add(valueReader);
139     return this;
140   }
141
142   @Override
143   public <T> Configuration addValueWriter(ValueWriter<T> valueWriter) {
144     getValueWriters().add(valueWriter);
145     return this;
146   }
147
148   @Override
149   public Configuration copy() {
150     return new InheritingConfiguration(thisfalse);
151   }
152
153   /**
154    * Determines equality from the name transformers, access levels and field matching configuration.
155    */

156   @Override
157   @SuppressWarnings("all")
158   public boolean equals(Object obj) {
159     if (this == obj)
160       return true;
161     if (obj == null || getClass() != obj.getClass())
162       return false;
163
164     InheritingConfiguration other = (InheritingConfiguration) obj;
165     if (!getSourceNameTransformer().equals(other.getSourceNameTransformer()))
166       return false;
167     if (!getDestinationNameTransformer().equals(other.getDestinationNameTransformer()))
168       return false;
169     if (getFieldAccessLevel() != other.getFieldAccessLevel())
170       return false;
171     if (getMethodAccessLevel() != other.getMethodAccessLevel())
172       return false;
173     if (isFieldMatchingEnabled() != other.isFieldMatchingEnabled())
174       return false;
175     return true;
176   }
177
178   @Override
179   public List<ConditionalConverter<?, ?>> getConverters() {
180     return converterStore.getConverters();
181   }
182
183   @Override
184   public NameTokenizer getDestinationNameTokenizer() {
185     return destinationNameTokenizer == null
186         ? Assert.notNull(parent).getDestinationNameTokenizer()
187         : destinationNameTokenizer;
188   }
189
190   @Override
191   public NameTransformer getDestinationNameTransformer() {
192     return destinationNameTransformer == null
193         ? Assert.notNull(parent).getDestinationNameTransformer()
194         : destinationNameTransformer;
195   }
196
197   @Override
198   public NamingConvention getDestinationNamingConvention() {
199     return destinationNamingConvention == null
200         ? Assert.notNull(parent).getDestinationNamingConvention()
201         : destinationNamingConvention;
202   }
203
204   @Override
205   public AccessLevel getFieldAccessLevel() {
206     return fieldAccessLevel == null
207         ? Assert.notNull(parent).getFieldAccessLevel()
208         : fieldAccessLevel;
209   }
210
211   @Override
212   public MatchingStrategy getMatchingStrategy() {
213     return matchingStrategy == null
214         ? Assert.notNull(parent).getMatchingStrategy()
215         : matchingStrategy;
216   }
217
218   @Override
219   public AccessLevel getMethodAccessLevel() {
220     return methodAccessLevel == null
221         ? Assert.notNull(parent).getMethodAccessLevel()
222         : methodAccessLevel;
223   }
224
225   @Override
226   public Condition<?, ?> getPropertyCondition() {
227     if (parent != null)
228       return propertyCondition == null
229           ? parent.getPropertyCondition()
230           : propertyCondition;
231     return propertyCondition;
232   }
233
234   @Override
235   public Provider<?> getProvider() {
236     if (parent != null)
237       return provider == null
238           ? Assert.notNull(parent).getProvider()
239           : provider;
240     return provider;
241   }
242
243   @Override
244   public NameTokenizer getSourceNameTokenizer() {
245     return sourceNameTokenizer == null
246         ? Assert.notNull(parent).getSourceNameTokenizer()
247         : sourceNameTokenizer;
248   }
249
250   @Override
251   public NameTransformer getSourceNameTransformer() {
252     return sourceNameTransformer == null
253         ? Assert.notNull(parent).getSourceNameTransformer()
254         : sourceNameTransformer;
255   }
256
257   @Override
258   public NamingConvention getSourceNamingConvention() {
259     return sourceNamingConvention == null
260         ? Assert.notNull(parent).getSourceNamingConvention()
261         : sourceNamingConvention;
262   }
263
264   @Override
265   public List<ValueReader<?>> getValueReaders() {
266     return valueAccessStore.getValueReaders();
267   }
268
269   @Override
270   public List<ValueWriter<?>> getValueWriters() {
271     return valueMutateStore.getValueWriters();
272   }
273
274   /**
275    * Produces a hash code from the name transformers, access levels and field matching
276    * configuration.
277    */

278   @Override
279   public int hashCode() {
280     final int prime = 31;
281     int result = 1;
282     result = prime * result + getSourceNameTransformer().hashCode();
283     result = prime * result + getDestinationNameTransformer().hashCode();
284     result = prime * result + getFieldAccessLevel().hashCode();
285     result = prime * result + getMethodAccessLevel().hashCode();
286     result = prime * result + (isFieldMatchingEnabled() ? 1231 : 1237);
287     return result;
288   }
289
290   @Override
291   public boolean isAmbiguityIgnored() {
292     return ambiguityIgnored == null
293         ? Assert.notNull(parent).isAmbiguityIgnored()
294         : ambiguityIgnored;
295   }
296
297   @Override
298   public boolean isFieldMatchingEnabled() {
299     return fieldMatchingEnabled == null
300         ? Assert.notNull(parent).isFieldMatchingEnabled()
301         : fieldMatchingEnabled;
302   }
303
304   @Override
305   public boolean isFullTypeMatchingRequired() {
306     return fullTypeMatchingRequired == null
307         ? Assert.notNull(parent).isFullTypeMatchingRequired()
308         : fullTypeMatchingRequired;
309   }
310
311   @Override
312   public boolean isImplicitMappingEnabled() {
313     return implicitMatchingEnabled == null
314         ? Assert.notNull(parent).isImplicitMappingEnabled()
315         : implicitMatchingEnabled;
316   }
317
318   @Override
319   public boolean isPreferNestedProperties() {
320     return preferNestedProperties == null
321         ? Assert.notNull(parent).isPreferNestedProperties()
322         : preferNestedProperties;
323   }
324
325   @Override
326   public boolean isSkipNullEnabled() {
327     return skipNullEnabled == null
328         ? Assert.notNull(parent).isSkipNullEnabled()
329         : skipNullEnabled;
330   }
331
332   @Override
333   public boolean isUseOSGiClassLoaderBridging() {
334     return useOSGiClassLoaderBridging == null
335         ? Assert.notNull(parent).isUseOSGiClassLoaderBridging()
336         : useOSGiClassLoaderBridging;
337   }
338
339   @Override
340   public boolean isDeepCopyEnabled() {
341     return !converterStore.hasConverter(AssignableConverter.class);
342   }
343
344   @Override
345   public boolean isCollectionsMergeEnabled() {
346     return converterStore.hasConverter(MergingCollectionConverter.class);
347   }
348
349   @Override
350   public Configuration setAmbiguityIgnored(boolean ignore) {
351     this.ambiguityIgnored = ignore;
352     return this;
353   }
354
355   @Override
356   public Configuration setDestinationNameTokenizer(NameTokenizer nameTokenizer) {
357     destinationNameTokenizer = Assert.notNull(nameTokenizer);
358     return this;
359   }
360
361   @Override
362   public Configuration setDestinationNameTransformer(NameTransformer nameTransformer) {
363     destinationNameTransformer = Assert.notNull(nameTransformer);
364     return this;
365   }
366
367   @Override
368   public Configuration setDestinationNamingConvention(NamingConvention namingConvention) {
369     destinationNamingConvention = Assert.notNull(namingConvention);
370     return this;
371   }
372
373   @Override
374   public Configuration setFieldAccessLevel(AccessLevel accessLevel) {
375     fieldAccessLevel = Assert.notNull(accessLevel);
376     return this;
377   }
378
379   @Override
380   public Configuration setFieldMatchingEnabled(boolean enabled) {
381     fieldMatchingEnabled = enabled;
382     return this;
383   }
384
385   @Override
386   public Configuration setFullTypeMatchingRequired(boolean required) {
387     fullTypeMatchingRequired = required;
388     return this;
389   }
390
391   @Override
392   public Configuration setImplicitMappingEnabled(boolean enabled) {
393     implicitMatchingEnabled = enabled;
394     return this;
395   }
396
397   @Override
398   public Configuration setPreferNestedProperties(boolean enabled) {
399     preferNestedProperties = enabled;
400     return this;
401   }
402
403   @Override
404   public Configuration setSkipNullEnabled(boolean enabled) {
405     skipNullEnabled = enabled;
406     return this;
407   }
408
409   @Override
410   public Configuration setDeepCopyEnabled(boolean enabled) {
411     if (enabled && converterStore.hasConverter(AssignableConverter.class))
412       converterStore.removeConverter(AssignableConverter.class);
413     else if (!enabled && !converterStore.hasConverter(AssignableConverter.class))
414       converterStore.addConverter(new AssignableConverter());
415     return this;
416   }
417
418   @Override
419   public Configuration setCollectionsMergeEnabled(boolean enabled) {
420     if (enabled) {
421       converterStore.replaceConverter(NonMergingCollectionConverter.classnew MergingCollectionConverter());
422     } else {
423       converterStore.replaceConverter(MergingCollectionConverter.classnew NonMergingCollectionConverter());
424     }
425     return this;
426   }
427
428   @Override
429   public Configuration setMatchingStrategy(MatchingStrategy matchingStrategy) {
430     this.matchingStrategy = Assert.notNull(matchingStrategy);
431     return this;
432   }
433
434   @Override
435   public Configuration setMethodAccessLevel(AccessLevel accessLevel) {
436     methodAccessLevel = Assert.notNull(accessLevel);
437     return this;
438   }
439
440   @Override
441   public Configuration setPropertyCondition(Condition<?, ?> condition) {
442     propertyCondition = Assert.notNull(condition);
443     return this;
444   }
445
446   @Override
447   public Configuration setProvider(Provider<?> provider) {
448     this.provider = Assert.notNull(provider);
449     return this;
450   }
451
452   @Override
453   public Configuration setSourceNameTokenizer(NameTokenizer nameTokenizer) {
454     sourceNameTokenizer = Assert.notNull(nameTokenizer);
455     return this;
456   }
457
458   @Override
459   public Configuration setSourceNameTransformer(NameTransformer nameTransformer) {
460     sourceNameTransformer = Assert.notNull(nameTransformer);
461     return this;
462   }
463
464   @Override
465   public Configuration setSourceNamingConvention(NamingConvention namingConvention) {
466     sourceNamingConvention = Assert.notNull(namingConvention);
467     return this;
468   }
469
470   @Override
471   public Configuration setUseOSGiClassLoaderBridging(boolean useOSGiClassLoaderBridging) {
472     this.useOSGiClassLoaderBridging = useOSGiClassLoaderBridging;
473     return this;
474   }
475 }
476