1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.dozer; |
17 | |
|
18 | |
import org.dozer.cache.CacheManager; |
19 | |
import org.dozer.cache.DozerCacheManager; |
20 | |
import org.dozer.cache.DozerCacheType; |
21 | |
import org.dozer.classmap.ClassMappings; |
22 | |
import org.dozer.classmap.Configuration; |
23 | |
import org.dozer.classmap.MappingFileData; |
24 | |
import org.dozer.config.GlobalSettings; |
25 | |
import org.dozer.event.DozerEventManager; |
26 | |
import org.dozer.factory.DestBeanCreator; |
27 | |
import org.dozer.loader.CustomMappingsLoader; |
28 | |
import org.dozer.loader.LoadMappingsResult; |
29 | |
import org.dozer.loader.api.BeanMappingBuilder; |
30 | |
import org.dozer.loader.xml.MappingFileReader; |
31 | |
import org.dozer.loader.xml.MappingStreamReader; |
32 | |
import org.dozer.loader.xml.XMLParserFactory; |
33 | |
import org.dozer.metadata.DozerMappingMetadata; |
34 | |
import org.dozer.metadata.MappingMetadata; |
35 | |
import org.dozer.stats.GlobalStatistics; |
36 | |
import org.dozer.stats.StatisticType; |
37 | |
import org.dozer.stats.StatisticsInterceptor; |
38 | |
import org.dozer.stats.StatisticsManager; |
39 | |
import org.dozer.util.MappingValidator; |
40 | |
import org.slf4j.Logger; |
41 | |
import org.slf4j.LoggerFactory; |
42 | |
|
43 | |
import java.io.InputStream; |
44 | |
import java.lang.reflect.Proxy; |
45 | |
import java.net.URL; |
46 | |
import java.util.*; |
47 | |
import java.util.concurrent.CountDownLatch; |
48 | |
import java.util.concurrent.atomic.AtomicBoolean; |
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
public class DozerBeanMapper implements Mapper { |
66 | |
|
67 | 1134 | private final Logger log = LoggerFactory.getLogger(DozerBeanMapper.class); |
68 | |
|
69 | 1134 | private final StatisticsManager statsMgr = GlobalStatistics.getInstance().getStatsMgr(); |
70 | 1134 | private final AtomicBoolean initializing = new AtomicBoolean(false); |
71 | 1134 | private final CountDownLatch ready = new CountDownLatch(1); |
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | 1134 | private final List<String> mappingFiles = new ArrayList<String>(); |
77 | 1134 | private final List<CustomConverter> customConverters = new ArrayList<CustomConverter>(); |
78 | 1134 | private final List<MappingFileData> builderMappings = new ArrayList<MappingFileData>(); |
79 | 1134 | private final List<DozerEventListener> eventListeners = new ArrayList<DozerEventListener>(); |
80 | 1134 | private final Map<String, CustomConverter> customConvertersWithId = new HashMap<String, CustomConverter>(); |
81 | |
|
82 | |
private CustomFieldMapper customFieldMapper; |
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
private ClassMappings customMappings; |
88 | |
private Configuration globalConfiguration; |
89 | |
|
90 | 1134 | private final CacheManager cacheManager = new DozerCacheManager(); |
91 | |
private DozerEventManager eventManager; |
92 | |
|
93 | |
public DozerBeanMapper() { |
94 | 1105 | this(Collections.<String>emptyList()); |
95 | 1105 | } |
96 | |
|
97 | 1134 | public DozerBeanMapper(List<String> mappingFiles) { |
98 | 1134 | this.mappingFiles.addAll(mappingFiles); |
99 | 1134 | init(); |
100 | 1134 | } |
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
public void map(Object source, Object destination, String mapId) throws MappingException { |
106 | 22 | getMappingProcessor().map(source, destination, mapId); |
107 | 22 | } |
108 | |
|
109 | |
|
110 | |
|
111 | |
|
112 | |
public <T> T map(Object source, Class<T> destinationClass, String mapId) throws MappingException { |
113 | 73 | return getMappingProcessor().map(source, destinationClass, mapId); |
114 | |
} |
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
public <T> T map(Object source, Class<T> destinationClass) throws MappingException { |
120 | 790 | return getMappingProcessor().map(source, destinationClass); |
121 | |
} |
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
public void map(Object source, Object destination) throws MappingException { |
127 | 131178 | getMappingProcessor().map(source, destination); |
128 | 131177 | } |
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | |
|
134 | |
|
135 | |
public List<String> getMappingFiles() { |
136 | 1 | return Collections.unmodifiableList(mappingFiles); |
137 | |
} |
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
public void setMappingFiles(List<String> mappingFileUrls) { |
148 | 592 | checkIfInitialized(); |
149 | 591 | this.mappingFiles.clear(); |
150 | 591 | this.mappingFiles.addAll(mappingFileUrls); |
151 | 591 | } |
152 | |
|
153 | |
public void setFactories(Map<String, BeanFactory> factories) { |
154 | 1 | checkIfInitialized(); |
155 | 0 | DestBeanCreator.setStoredFactories(factories); |
156 | 0 | } |
157 | |
|
158 | |
public void setCustomConverters(List<CustomConverter> customConverters) { |
159 | 3 | checkIfInitialized(); |
160 | 2 | this.customConverters.clear(); |
161 | 2 | this.customConverters.addAll(customConverters); |
162 | 2 | } |
163 | |
|
164 | |
public List<CustomConverter> getCustomConverters() { |
165 | 1 | return Collections.unmodifiableList(customConverters); |
166 | |
} |
167 | |
|
168 | |
public Map<String, CustomConverter> getCustomConvertersWithId() { |
169 | 1 | return Collections.unmodifiableMap(customConvertersWithId); |
170 | |
} |
171 | |
|
172 | |
private void init() { |
173 | 1134 | DozerInitializer.getInstance().init(); |
174 | |
|
175 | 1134 | log.info("Initializing a new instance of dozer bean mapper."); |
176 | |
|
177 | |
|
178 | |
|
179 | 1134 | GlobalSettings globalSettings = GlobalSettings.getInstance(); |
180 | 1134 | cacheManager.addCache(DozerCacheType.CONVERTER_BY_DEST_TYPE.name(), globalSettings.getConverterByDestTypeCacheMaxSize()); |
181 | 1134 | cacheManager.addCache(DozerCacheType.SUPER_TYPE_CHECK.name(), globalSettings.getSuperTypesCacheMaxSize()); |
182 | |
|
183 | |
|
184 | 1134 | statsMgr.increment(StatisticType.MAPPER_INSTANCES_COUNT); |
185 | 1134 | } |
186 | |
|
187 | |
public void destroy() { |
188 | 1 | DozerInitializer.getInstance().destroy(); |
189 | 1 | } |
190 | |
|
191 | |
protected Mapper getMappingProcessor() { |
192 | 132074 | initMappings(); |
193 | |
|
194 | 132059 | Mapper processor = new MappingProcessor(customMappings, globalConfiguration, cacheManager, statsMgr, customConverters, |
195 | |
eventManager, getCustomFieldMapper(), customConvertersWithId); |
196 | |
|
197 | |
|
198 | 132059 | if (statsMgr.isStatisticsEnabled()) { |
199 | 0 | processor = (Mapper) Proxy.newProxyInstance(processor.getClass().getClassLoader(), |
200 | |
processor.getClass().getInterfaces(), |
201 | |
new StatisticsInterceptor(processor, statsMgr)); |
202 | |
} |
203 | |
|
204 | 132059 | return processor; |
205 | |
} |
206 | |
|
207 | |
void loadCustomMappings() { |
208 | 698 | CustomMappingsLoader customMappingsLoader = new CustomMappingsLoader(); |
209 | 698 | List<MappingFileData> xmlMappings = loadFromFiles(mappingFiles); |
210 | 690 | ArrayList<MappingFileData> allMappings = new ArrayList<MappingFileData>(); |
211 | 690 | allMappings.addAll(xmlMappings); |
212 | 690 | allMappings.addAll(builderMappings); |
213 | 690 | LoadMappingsResult loadMappingsResult = customMappingsLoader.load(allMappings); |
214 | 683 | this.customMappings = loadMappingsResult.getCustomMappings(); |
215 | 683 | this.globalConfiguration = loadMappingsResult.getGlobalConfiguration(); |
216 | 683 | } |
217 | |
|
218 | |
private List<MappingFileData> loadFromFiles(List<String> mappingFiles) { |
219 | 698 | MappingFileReader mappingFileReader = new MappingFileReader(XMLParserFactory.getInstance()); |
220 | 698 | List<MappingFileData> mappingFileDataList = new ArrayList<MappingFileData>(); |
221 | 698 | if (mappingFiles != null && mappingFiles.size() > 0) { |
222 | 594 | log.info("Using the following xml files to load custom mappings for the bean mapper instance: {}", mappingFiles); |
223 | 594 | for (String mappingFileName : mappingFiles) { |
224 | 600 | log.info("Trying to find xml mapping file: {}", mappingFileName); |
225 | 600 | URL url = MappingValidator.validateURL(mappingFileName); |
226 | 600 | log.info("Using URL [" + url + "] to load custom xml mappings"); |
227 | 600 | MappingFileData mappingFileData = mappingFileReader.read(url); |
228 | 592 | log.info("Successfully loaded custom xml mappings from URL: [{}]", url); |
229 | |
|
230 | 592 | mappingFileDataList.add(mappingFileData); |
231 | 592 | } |
232 | |
} |
233 | 690 | return mappingFileDataList; |
234 | |
} |
235 | |
|
236 | |
|
237 | |
|
238 | |
|
239 | |
|
240 | |
|
241 | |
|
242 | |
|
243 | |
|
244 | |
public void addMapping(InputStream xmlStream) { |
245 | 1 | checkIfInitialized(); |
246 | 0 | MappingStreamReader fileReader = new MappingStreamReader(XMLParserFactory.getInstance()); |
247 | 0 | MappingFileData mappingFileData = fileReader.read(xmlStream); |
248 | 0 | builderMappings.add(mappingFileData); |
249 | 0 | } |
250 | |
|
251 | |
|
252 | |
|
253 | |
|
254 | |
|
255 | |
|
256 | |
public void addMapping(BeanMappingBuilder mappingBuilder) { |
257 | 28 | checkIfInitialized(); |
258 | 27 | MappingFileData mappingFileData = mappingBuilder.build(); |
259 | 27 | builderMappings.add(mappingFileData); |
260 | 27 | } |
261 | |
|
262 | |
public List<? extends DozerEventListener> getEventListeners() { |
263 | 2 | return Collections.unmodifiableList(eventListeners); |
264 | |
} |
265 | |
|
266 | |
public void setEventListeners(List<? extends DozerEventListener> eventListeners) { |
267 | 2 | checkIfInitialized(); |
268 | 1 | this.eventListeners.clear(); |
269 | 1 | this.eventListeners.addAll(eventListeners); |
270 | 1 | } |
271 | |
|
272 | |
public CustomFieldMapper getCustomFieldMapper() { |
273 | 132059 | return customFieldMapper; |
274 | |
} |
275 | |
|
276 | |
public void setCustomFieldMapper(CustomFieldMapper customFieldMapper) { |
277 | 3 | checkIfInitialized(); |
278 | 2 | this.customFieldMapper = customFieldMapper; |
279 | 2 | } |
280 | |
|
281 | |
|
282 | |
|
283 | |
|
284 | |
|
285 | |
|
286 | |
|
287 | |
|
288 | |
|
289 | |
public MappingMetadata getMappingMetadata() { |
290 | 48 | initMappings(); |
291 | 48 | return new DozerMappingMetadata(customMappings); |
292 | |
} |
293 | |
|
294 | |
|
295 | |
|
296 | |
|
297 | |
|
298 | |
|
299 | |
|
300 | |
public void setCustomConvertersWithId(Map<String, CustomConverter> customConvertersWithId) { |
301 | 5 | checkIfInitialized(); |
302 | 4 | this.customConvertersWithId.clear(); |
303 | 4 | this.customConvertersWithId.putAll(customConvertersWithId); |
304 | 4 | } |
305 | |
|
306 | |
private void checkIfInitialized() { |
307 | 635 | if (ready.getCount() == 0) { |
308 | 8 | throw new MappingException("Dozer Bean Mapper is already initialized! Modify settings before calling map()"); |
309 | |
} |
310 | 627 | } |
311 | |
|
312 | |
private void initMappings() { |
313 | 132122 | if (initializing.compareAndSet(false, true)) { |
314 | |
try { |
315 | 699 | loadCustomMappings(); |
316 | 684 | eventManager = new DozerEventManager(eventListeners); |
317 | 15 | } catch (RuntimeException e) { |
318 | |
|
319 | 15 | initializing.set(false); |
320 | 15 | throw e; |
321 | |
} finally { |
322 | 699 | ready.countDown(); |
323 | 684 | } |
324 | |
} |
325 | |
|
326 | |
try { |
327 | 132107 | ready.await(); |
328 | 0 | } catch (InterruptedException e) { |
329 | 0 | log.error("Thread interrupted: ", e); |
330 | |
|
331 | 0 | Thread.currentThread().interrupt(); |
332 | 132107 | } |
333 | 132107 | } |
334 | |
|
335 | |
} |