Skip to content

Commit 28bb619

Browse files
authored
Updated spring to be compliant with builder pattern (#481)
1 parent 8c30bed commit 28bb619

File tree

9 files changed

+138
-191
lines changed

9 files changed

+138
-191
lines changed

spring/src/main/java/com/github/dozermapper/spring/DozerBeanMapperFactoryBean.java

Lines changed: 83 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.net.URL;
2020
import java.util.ArrayList;
21+
import java.util.Arrays;
2122
import java.util.HashMap;
2223
import java.util.List;
2324
import java.util.Map;
@@ -40,177 +41,144 @@
4041

4142
/**
4243
* Public Spring FactoryBean that can be used by application code.
43-
* Uses Spring InitializingBean and DisposableBean contracts to properly start-up and
44-
* release global Dozer resources.
44+
* Uses Spring InitializingBean contracts to properly start-up
4545
*
4646
* @author S'ren Chittka
4747
* @author dmitry.buzdin
4848
*/
49-
public class DozerBeanMapperFactoryBean implements FactoryBean<Mapper>,
50-
InitializingBean, DisposableBean, ApplicationContextAware {
49+
public class DozerBeanMapperFactoryBean implements ApplicationContextAware, InitializingBean, FactoryBean<Mapper> {
5150

52-
DozerBeanMapper beanMapper;
53-
private Resource[] mappingFiles;
54-
private List<BeanMappingBuilder> mappingBuilders;
55-
private CustomFieldMapper customFieldMapper;
56-
private List<CustomConverter> customConverters;
57-
private Map<String, CustomConverter> customConvertersWithId;
58-
private List<DozerEventListener> eventListeners;
59-
private Map<String, BeanFactory> factories;
6051
private ApplicationContext applicationContext;
6152

53+
private CustomFieldMapper customFieldMapper;
54+
private List<String> mappingFileUrls = new ArrayList<>(1);
55+
private List<CustomConverter> customConverters = new ArrayList<>(0);
56+
private List<BeanMappingBuilder> mappingBuilders = new ArrayList<>(0);
57+
private List<DozerEventListener> eventListeners = new ArrayList<>(0);
58+
private Map<String, BeanFactory> beanFactories = new HashMap<>(0);
59+
private Map<String, CustomConverter> customConvertersWithId = new HashMap<>(0);
60+
61+
private Mapper mapper;
62+
63+
public void setCustomFieldMapper(CustomFieldMapper customFieldMapper) {
64+
this.customFieldMapper = customFieldMapper;
65+
}
66+
6267
/**
6368
* Spring resources definition for providing mapping file location.
6469
* Could be used for loading all mapping files by wildcard definition for example
70+
*
6571
* {@code
6672
* <bean class="org.dozer.spring.DozerBeanMapperFactoryBean">
67-
* <property name="mappingFiles" value="classpath*:/*.dozer.xml"/>
73+
* <property name="mappingFiles" value="classpath*:/*.dozer.xml"/>
6874
* </bean>
6975
* }
7076
*
7177
* @param mappingFiles Spring resource definition
78+
* @throws IOException if URL fails to resolve
7279
*/
73-
public final void setMappingFiles(final Resource[] mappingFiles) {
74-
this.mappingFiles = mappingFiles;
75-
}
76-
77-
public final void setMappingBuilders(final List<BeanMappingBuilder> mappingBuilders) {
78-
this.mappingBuilders = mappingBuilders;
79-
}
80-
81-
public void setCustomFieldMapper(CustomFieldMapper customFieldMapper) {
82-
this.customFieldMapper = customFieldMapper;
80+
public void setMappingFiles(Resource[] mappingFiles) throws IOException {
81+
if (mappingFiles != null && mappingFiles.length > 0) {
82+
for (Resource mappingFile : mappingFiles) {
83+
URL url = mappingFile.getURL();
84+
mappingFileUrls.add(url.toString());
85+
}
86+
}
8387
}
8488

85-
public final void setCustomConverters(final List<CustomConverter> customConverters) {
86-
this.customConverters = customConverters;
89+
public void setCustomConverters(List<CustomConverter> customConverters) {
90+
this.customConverters.addAll(customConverters);
8791
}
8892

89-
public void setCustomConvertersWithId(Map<String, CustomConverter> customConvertersWithId) {
90-
this.customConvertersWithId = customConvertersWithId;
93+
public void setMappingBuilders(List<BeanMappingBuilder> mappingBuilders) {
94+
this.mappingBuilders.addAll(mappingBuilders);
9195
}
9296

93-
public final void setEventListeners(final List<DozerEventListener> eventListeners) {
94-
this.eventListeners = eventListeners;
97+
public void setEventListeners(List<DozerEventListener> eventListeners) {
98+
this.eventListeners.addAll(eventListeners);
9599
}
96100

97-
public final void setFactories(final Map<String, BeanFactory> factories) {
98-
this.factories = factories;
101+
public void setFactories(Map<String, BeanFactory> beanFactories) {
102+
this.beanFactories.putAll(beanFactories);
99103
}
100104

101-
// ==================================================================================================================================
102-
// interface 'FactoryBean'
103-
// ==================================================================================================================================
104-
public final Mapper getObject() throws Exception {
105-
return this.beanMapper;
105+
public void setCustomConvertersWithId(Map<String, CustomConverter> customConvertersWithId) {
106+
this.customConvertersWithId.putAll(customConvertersWithId);
106107
}
107108

108-
public final Class<Mapper> getObjectType() {
109-
return Mapper.class;
110-
}
109+
// ===
110+
// Methods for: ApplicationContextAware
111+
// ===
111112

112-
public final boolean isSingleton() {
113-
return true;
113+
@Override
114+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
115+
this.applicationContext = applicationContext;
114116
}
115117

116-
// ==================================================================================================================================
117-
// interface 'InitializingBean'
118-
// ==================================================================================================================================
119-
public final void afterPropertiesSet() throws Exception {
120-
// todo to be reworked in #402
121-
this.beanMapper = (DozerBeanMapper) DozerBeanMapperBuilder.buildDefault();
122-
123-
loadMappingFiles();
118+
// ===
119+
// Methods for: InitializingBean
120+
// ===
124121

125-
List<CustomConverter> allConverters = new ArrayList<CustomConverter>();
126-
Map<String, CustomConverter> allIdConverters = new HashMap<String, CustomConverter>();
127-
Map<String, BeanFactory> allFactories = new HashMap<String, BeanFactory>();
128-
List<DozerEventListener> allListeners = new ArrayList<DozerEventListener>();
129-
List<BeanMappingBuilder> allMappingBuilders = new ArrayList<BeanMappingBuilder>();
130-
131-
Map<String, CustomConverter> contextConverters = applicationContext.getBeansOfType(CustomConverter.class);
132-
Map<String, BeanFactory> contextBeanFactories = applicationContext.getBeansOfType(BeanFactory.class);
122+
@Override
123+
public void afterPropertiesSet() throws Exception {
124+
Map<String, CustomConverter> contextCustomConvertersWithId = applicationContext.getBeansOfType(CustomConverter.class);
125+
Map<String, BeanMappingBuilder> contextBeanMappingBuilders = applicationContext.getBeansOfType(BeanMappingBuilder.class);
133126
Map<String, DozerEventListener> contextEventListeners = applicationContext.getBeansOfType(DozerEventListener.class);
134-
Map<String, BeanMappingBuilder> contextMappingBuilders = applicationContext.getBeansOfType(BeanMappingBuilder.class);
135-
136-
allConverters.addAll(contextConverters.values());
137-
allIdConverters.putAll(contextConverters);
138-
allFactories.putAll(contextBeanFactories);
139-
allListeners.addAll(contextEventListeners.values());
140-
allMappingBuilders.addAll(contextMappingBuilders.values());
141-
142-
if (customFieldMapper != null) {
143-
this.beanMapper.setCustomFieldMapper(customFieldMapper);
144-
}
127+
Map<String, BeanFactory> contextBeanFactorys = applicationContext.getBeansOfType(BeanFactory.class);
145128

146-
if (this.customConverters != null) {
147-
allConverters.addAll(this.customConverters);
148-
}
129+
customConverters.addAll(contextCustomConvertersWithId.values());
130+
mappingBuilders.addAll(contextBeanMappingBuilders.values());
131+
beanFactories.putAll(contextBeanFactorys);
132+
eventListeners.addAll(contextEventListeners.values());
133+
customConvertersWithId.putAll(contextCustomConvertersWithId);
149134

150-
if (this.customConvertersWithId != null) {
151-
allIdConverters.putAll(this.customConvertersWithId);
152-
}
135+
DozerBeanMapperBuilder builder = DozerBeanMapperBuilder.create();
153136

154-
if (this.eventListeners != null) {
155-
allListeners.addAll(this.eventListeners);
137+
for (String url : mappingFileUrls) {
138+
builder.withMappingFiles(url);
156139
}
157140

158-
if (this.factories != null) {
159-
allFactories.putAll(this.factories);
160-
}
141+
builder.withCustomFieldMapper(customFieldMapper);
161142

162-
if (this.mappingBuilders != null) {
163-
allMappingBuilders.addAll(this.mappingBuilders);
143+
for (CustomConverter converter : customConverters) {
144+
builder.withCustomConverter(converter);
164145
}
165146

166-
if (!allConverters.isEmpty()) {
167-
this.beanMapper.setCustomConverters(allConverters);
147+
for (BeanMappingBuilder mappingBuilder : mappingBuilders) {
148+
builder.withMappingBuilder(mappingBuilder);
168149
}
169150

170-
if (!allIdConverters.isEmpty()) {
171-
this.beanMapper.setCustomConvertersWithId(allIdConverters);
151+
for (DozerEventListener listener : eventListeners) {
152+
builder.withEventListener(listener);
172153
}
173154

174-
if (!allFactories.isEmpty()) {
175-
this.beanMapper.setFactories(allFactories);
155+
for (Map.Entry<String, BeanFactory> beanFactoryEntry : beanFactories.entrySet()) {
156+
builder.withBeanFactory(beanFactoryEntry.getKey(), beanFactoryEntry.getValue());
176157
}
177158

178-
if (!allListeners.isEmpty()) {
179-
this.beanMapper.setEventListeners(allListeners);
159+
for (Map.Entry<String, CustomConverter> customConverterEntry : customConvertersWithId.entrySet()) {
160+
builder.withCustomConverterWithId(customConverterEntry.getKey(), customConverterEntry.getValue());
180161
}
181162

182-
if (!allMappingBuilders.isEmpty()) {
183-
for (BeanMappingBuilder mappingBuilder : allMappingBuilders) {
184-
this.beanMapper.addMapping(mappingBuilder);
185-
}
186-
}
163+
this.mapper = builder.build();
187164
}
188165

189-
private void loadMappingFiles() throws IOException {
190-
if (this.mappingFiles != null) {
191-
final List<String> mappings = new ArrayList<String>(this.mappingFiles.length);
192-
for (Resource mappingFile : this.mappingFiles) {
193-
URL url = mappingFile.getURL();
194-
mappings.add(url.toString());
195-
}
166+
// ===
167+
// Methods for: FactoryBean<Mapper>
168+
// ===
196169

197-
this.beanMapper.setMappingFiles(mappings);
198-
}
170+
@Override
171+
public Mapper getObject() throws Exception {
172+
return this.mapper;
199173
}
200174

201-
/**
202-
* Spring DisposableBean method implementation. Triggered when application context is stopped.
203-
* Used to release global Dozer resources for hot redeployment without stopping the JVM.
204-
*
205-
* @throws Exception if bean mapper fails to destory
206-
*/
207-
public void destroy() throws Exception {
208-
if (this.beanMapper != null) {
209-
this.beanMapper.destroy();
210-
}
175+
@Override
176+
public Class<Mapper> getObjectType() {
177+
return Mapper.class;
211178
}
212179

213-
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
214-
this.applicationContext = applicationContext;
180+
@Override
181+
public boolean isSingleton() {
182+
return true;
215183
}
216184
}

spring/src/test/java/com/github/dozermapper/spring/DozerBeanMapperFactoryBeanTest.java

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,24 @@
2626
import org.dozer.DozerEventListener;
2727
import org.dozer.Mapper;
2828
import org.dozer.loader.api.BeanMappingBuilder;
29-
import org.junit.Assert;
3029
import org.junit.Before;
3130
import org.junit.Test;
3231
import org.springframework.context.ApplicationContext;
3332
import org.springframework.core.io.Resource;
3433

35-
import static org.hamcrest.CoreMatchers.equalTo;
3634
import static org.junit.Assert.assertEquals;
37-
import static org.junit.Assert.assertThat;
35+
import static org.junit.Assert.assertTrue;
3836
import static org.mockito.Mockito.mock;
39-
import static org.mockito.Mockito.verify;
4037
import static org.mockito.Mockito.when;
4138

4239
/**
4340
* @author <a href="mailto:[email protected]">Dmitry Buzdin</a>
4441
*/
4542
public class DozerBeanMapperFactoryBeanTest {
4643

47-
DozerBeanMapperFactoryBean factory;
48-
Resource mockResource;
49-
ApplicationContext mockContext;
44+
private DozerBeanMapperFactoryBean factory;
45+
private Resource mockResource;
46+
private ApplicationContext mockContext;
5047

5148
@Before
5249
public void setUp() throws Exception {
@@ -58,23 +55,24 @@ public void setUp() throws Exception {
5855

5956
@Test
6057
public void testOk() throws Exception {
58+
URL url = this.getClass().getClassLoader().getResource("mappings/mappingSpring.xml");
59+
when(mockResource.getURL()).thenReturn(url);
60+
6161
factory.setCustomConverters(Collections.EMPTY_LIST);
6262
factory.setCustomConvertersWithId(Collections.EMPTY_MAP);
6363
factory.setEventListeners(Collections.EMPTY_LIST);
6464
factory.setFactories(Collections.EMPTY_MAP);
6565
factory.setMappingFiles(new Resource[] {mockResource});
6666
factory.setMappingBuilders(Collections.EMPTY_LIST);
6767

68-
URL url = this.getClass().getClassLoader().getResource("mappings/mappingSpring.xml");
69-
when(mockResource.getURL()).thenReturn(url);
70-
7168
factory.afterPropertiesSet();
7269

7370
assertEquals(Mapper.class, factory.getObjectType());
74-
Assert.assertTrue(factory.isSingleton());
71+
assertTrue(factory.isSingleton());
7572

7673
DozerBeanMapper mapper = (DozerBeanMapper)factory.getObject();
7774
List<?> files = mapper.getMappingFiles();
75+
7876
assertEquals(1, files.size());
7977
assertEquals("file:" + url.getFile(), files.iterator().next());
8078
}
@@ -84,21 +82,17 @@ public void testEmpty() throws Exception {
8482
factory.afterPropertiesSet();
8583
}
8684

87-
@Test
88-
public void testDestroy() throws Exception {
89-
factory.beanMapper = mock(DozerBeanMapper.class);
90-
factory.destroy();
91-
verify(factory.beanMapper).destroy();
92-
}
93-
9485
@Test
9586
public void shouldInjectBeans() throws Exception {
9687
HashMap<String, CustomConverter> converterHashMap = new HashMap<String, CustomConverter>();
9788
converterHashMap.put("a", mock(CustomConverter.class));
89+
9890
HashMap<String, BeanFactory> beanFactoryMap = new HashMap<String, BeanFactory>();
9991
beanFactoryMap.put("a", mock(BeanFactory.class));
92+
10093
HashMap<String, DozerEventListener> eventListenerMap = new HashMap<String, DozerEventListener>();
10194
eventListenerMap.put("a", mock(DozerEventListener.class));
95+
10296
HashMap<String, BeanMappingBuilder> mappingBuilders = new HashMap<String, BeanMappingBuilder>();
10397
mappingBuilders.put("a", mock(BeanMappingBuilder.class));
10498

@@ -110,11 +104,9 @@ public void shouldInjectBeans() throws Exception {
110104
factory.afterPropertiesSet();
111105

112106
DozerBeanMapper mapper = (DozerBeanMapper)factory.getObject();
113-
assertThat(mapper.getCustomConverters().size(), equalTo(1));
114-
assertThat(mapper.getCustomConverters().size(), equalTo(1));
115-
assertThat(mapper.getCustomConvertersWithId().size(), equalTo(1));
116-
assertThat(mapper.getEventListeners().size(), equalTo(1));
117-
// FIXME: there's no mapper.getMappings() method,
118-
// so there's no (easy) way to verify whether BeanMappingBuilder was injected!
107+
assertEquals(1, mapper.getCustomConverters().size());
108+
assertEquals(1, mapper.getCustomConverters().size());
109+
assertEquals(1, mapper.getCustomConvertersWithId().size());
110+
assertEquals(1, mapper.getEventListeners().size());
119111
}
120112
}

0 commit comments

Comments
 (0)