1
16 package org.modelmapper.internal;
17
18 import org.modelmapper.Converter;
19 import org.modelmapper.PropertyMap;
20 import org.modelmapper.TypeMap;
21 import org.modelmapper.internal.util.Primitives;
22 import org.modelmapper.internal.util.Types;
23
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.ConcurrentHashMap;
30
31
34 public final class TypeMapStore {
35 private final Map<TypePair<?, ?>, TypeMap<?, ?>> typeMaps = new ConcurrentHashMap<TypePair<?, ?>, TypeMap<?, ?>>();
36 private final Map<TypePair<?, ?>, TypeMap<?, ?>> immutableTypeMaps = Collections.unmodifiableMap(typeMaps);
37 private final Object lock = new Object();
38
39 private final InheritingConfiguration config;
40
41 TypeMapStore(InheritingConfiguration config) {
42 this.config = config;
43 }
44
45
49 public <S, D> TypeMap<S, D> create(S source, Class<S> sourceType, Class<D> destinationType,
50 String typeMapName, InheritingConfiguration configuration, MappingEngineImpl engine) {
51 synchronized (lock) {
52 TypeMapImpl<S, D> typeMap = new TypeMapImpl<S, D>(sourceType, destinationType, typeMapName,
53 configuration, engine);
54 if (configuration.isImplicitMappingEnabled()
55 && Types.mightContainsProperties(typeMap.getSourceType())
56 && Types.mightContainsProperties(typeMap.getDestinationType()))
57 ImplicitMappingBuilder.build(source, typeMap, config.typeMapStore, config.converterStore);
58 typeMaps.put(TypePair.of(sourceType, destinationType, typeMapName), typeMap);
59 return typeMap;
60 }
61 }
62
63
67 public <S, D> TypeMap<S, D> createEmptyTypeMap(Class<S> sourceType, Class<D> destinationType,
68 String typeMapName, InheritingConfiguration configuration, MappingEngineImpl engine) {
69 synchronized (lock) {
70 TypeMapImpl<S, D> typeMap = new TypeMapImpl<S, D>(sourceType, destinationType, typeMapName,
71 configuration, engine);
72 typeMaps.put(TypePair.of(sourceType, destinationType, typeMapName), typeMap);
73 return typeMap;
74 }
75 }
76
77 public Collection<TypeMap<?, ?>> get() {
78 return immutableTypeMaps.values();
79 }
80
81
85 @SuppressWarnings("unchecked")
86 public <S, D> TypeMap<S, D> get(Class<S> sourceType, Class<D> destinationType, String typeMapName) {
87 TypeMap<S, D> typeMap = getTypeMap(sourceType, destinationType, typeMapName);
88 if (typeMap != null)
89 return typeMap;
90
91 for (TypePair<?, ?> typePair : getPrimitiveWrapperTypePairs(sourceType, destinationType, typeMapName)) {
92 typeMap = (TypeMap<S, D>) typeMaps.get(typePair);
93 if (typeMap != null)
94 return typeMap;
95 }
96
97 return null;
98 }
99
100
104 public <S, D> TypeMap<S, D> getOrCreate(S source, Class<S> sourceType, Class<D> destinationType,
105 String typeMapName, MappingEngineImpl engine) {
106 return getOrCreate(source, sourceType, destinationType, typeMapName, null, null,
107 engine);
108 }
109
110
117 @SuppressWarnings("unchecked")
118 public <S, D> TypeMap<S, D> getOrCreate(S source, Class<S> sourceType, Class<D> destinationType,
119 String typeMapName, PropertyMap<S, D> propertyMap, Converter<S, D> converter,
120 MappingEngineImpl engine) {
121 synchronized (lock) {
122 TypeMapImpl<S, D> typeMap = getTypeMap(sourceType, destinationType, typeMapName);
123
124 if (typeMap == null) {
125 typeMap = new TypeMapImpl<S, D>(sourceType, destinationType, typeMapName, config, engine);
126 if (propertyMap != null)
127 typeMap.addMappings(propertyMap);
128 if (converter == null && config.isImplicitMappingEnabled()
129 && Types.mightContainsProperties(typeMap.getSourceType())
130 && Types.mightContainsProperties(typeMap.getDestinationType()))
131 ImplicitMappingBuilder.build(source, typeMap, config.typeMapStore, config.converterStore);
132
133 if (typeMap.isFullMatching()) {
134 typeMaps.put(TypePair.of(sourceType, destinationType, typeMapName), typeMap);
135 }
136 } else if (propertyMap != null) {
137 typeMap.addMappings(propertyMap);
138 }
139
140 if (converter != null)
141 typeMap.setConverter(converter);
142 return typeMap;
143 }
144 }
145
146
151 public void put(TypeMap<?, ?> typeMap) {
152 TypePair<?, ?> typePair = TypePair.of(typeMap.getSourceType(),
153 typeMap.getDestinationType(), typeMap.getName());
154 synchronized (lock) {
155 if (typeMaps.containsKey(typePair))
156 throw new IllegalArgumentException("TypeMap exists in the store: " + typePair.toString());
157 typeMaps.put(typePair, typeMap);
158 }
159 }
160
161
166 public <S, D> void put(Class<S> sourceType, Class<D> destinationType, TypeMap<S, ? extends D> typeMap) {
167 TypePair<S, D> typePair = TypePair.of(sourceType, destinationType,
168 typeMap.getName());
169 synchronized (lock) {
170 if (typeMaps.containsKey(typePair))
171 throw new IllegalArgumentException("TypeMap exists in the store: " + typePair.toString());
172 typeMaps.put(typePair, typeMap);
173 }
174 }
175
176 private <S, D> List<TypePair<?, ?>> getPrimitiveWrapperTypePairs(Class<S> sourceType, Class<D> destinationType, String typeMapName) {
177 List<TypePair<?, ?>> typePairs = new ArrayList<TypePair<?, ?>>(1);
178 if (Primitives.isPrimitive(sourceType)) {
179 typePairs.add(TypePair.of(Primitives.wrapperFor(sourceType), destinationType, typeMapName));
180 }
181 if (Primitives.isPrimitive(destinationType)) {
182 typePairs.add(TypePair.of(sourceType, Primitives.wrapperFor(destinationType), typeMapName));
183 }
184 if (Primitives.isPrimitive(sourceType) && Primitives.isPrimitiveWrapper(destinationType)) {
185 typePairs.add(TypePair.of(Primitives.wrapperFor(sourceType), Primitives.wrapperFor(destinationType), typeMapName));
186 }
187 return typePairs;
188 }
189
190 @SuppressWarnings("unchecked")
191 private <S, D> TypeMapImpl<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType, String typeMapName) {
192 TypePair<S, D> typePair = TypePair.of(sourceType, destinationType, typeMapName);
193
194 TypeMapImpl<S, D> typeMap = (TypeMapImpl<S, D>) typeMaps.get(typePair);
195 if (typeMap == null && isAnonymousEnumSubclass(sourceType)) {
196 typeMap = (TypeMapImpl<S, D>) typeMaps.get(
197 TypePair.of((Class<S>) sourceType.getSuperclass(), destinationType, typeMapName)
198 );
199 }
200
201 return typeMap;
202 }
203
204 private <S> boolean isAnonymousEnumSubclass(Class<S> sourceType) {
205 return sourceType.getSuperclass() != null
206 && sourceType.getSuperclass().isEnum()
207 && sourceType.isAnonymousClass();
208 }
209
210 }
211