问题
Is there a way to define a custom converter in Dozer for converting one top-level type to another, which is itself a Spring bean and thus can get its dependencies injected?
The dozer docs propose to add the following XML definition:
<converter type="org.dozer.converters.TestCustomConverter" >
<class-a>org.dozer.vo.CustomDoubleObject</class-a>
<class-b>java.lang.Double</class-b>
</converter>
Unfortunately, this causes Dozer to instantiate org.dozer.converters.TestCustomConverter
directly, which will skip dependency injection. Is there a way to reference a Spring bean instead?
回答1:
If your custom converter is a spring bean then the property 'customConvertersWithIds' of Dozer bean mapper can be used to refer to the converter spring bean. Then use this id to refer to the custom converter in the mappings. Here is how I made it work for me:
<bean id="dozerMapper" class="org.dozer.DozerBeanMapper" scope="singleton">
<property name="mappingFiles">
<list>
<value><mapping-file-name1></value>
<value><mapping-file-name2></value>
</list>
</property>
<property name="customConvertersWithId">
<map>
<entry key="crbConverter" value-ref="loadableFooBeanConverter"/>
<entry key="sbConverter" value-ref="loadableXyzBeanConverter"/>
</map>
</property>
</bean>
I have the converter classes annotated, e.g., @component("loadableFooBeanConverter")
An example of a mapping:
<mapping>
<class-a>${Abc}</class-a>
<class-b>${AbcBean}</class-b>
<field custom-converter-id="sbConverter">
<a>XyzId</a>
<b>Xyz</b>
<b-hint>${XyzBean}</b-hint>
</field>
</mapping>
回答2:
Next to CustomConverterWithIds as in previous answer it is also possible to inject custom converters to override the converters defined in the configuration part in the mapping file. That way dozer will use the injected converter instead of instantiating one using the default constructor.
<bean id="dozerMapper" class="org.dozer.DozerBeanMapper" scope="singleton">
<property name="mappingFiles">
<list>
<value><mapping-file-name1></value>
<value><mapping-file-name2></value>
</list>
</property>
<property name="customConverters">
<list>
<ref bean="entityConverter"/>
</list>
</property>
</bean>
<configuration>
<custom-converters>
<converter type="my.domain.EntityConverter">
<class-a>java.lang.Integer</class-a>
<class-b>my.domain.MyEntity</class-b>
</converter>
<custom-converters>
</configuration>
<beans .... >
<bean id="entityConverter" class="my.domain.EntityConverter">
<property ....
</bean
</beans>
回答3:
Unfortunately, this is not supported.
回答4:
To inject Spring bean as a custom converter I patched the original Dozer. You can review my changes and use them if they are acceptable for you. The updated sources are located on https://bitbucket.org/JRS/open-dozer.
You still need add custom converter record to the global configuration.
回答5:
To improve @Chris answer, you can refer class directly to avoid to declare a bean.
Declare your custom converter bean in the dozer bean declaration.
<bean id="DozerMapper" class="org.dozer.DozerBeanMapper">
<property name="mappingFiles">
<list>
<value>mapping.xml</value>
</list>
</property>
<property name="customConverters">
<list>
<bean class="com.pharmagest.monalisa.rest.service.mapper.MyConverter"/>
</list>
</property>
</bean>
After declare your mapping in the configuration (for me, in the mapping.xml file).
<configuration>
<stop-on-errors>true</stop-on-errors>
<date-format>MM/dd/yyyy HH:mm</date-format>
<wildcard>true</wildcard>
<custom-converters>
<converter type="com.pharmagest.monalisa.rest.service.mapper.MyConverter">
<class-a>com.project.ClassA</class-a>
<class-b>com.project.ClassB</class-b>
</converter>
</custom-converters>
</configuration>
回答6:
The Java configuration in Spring Boot for Gunjan's answer can be as following:
Create the custom converter as a bean as below:
@Component
public class LoadableFooBeanConverter extends DozerConverter<BarBean, FooBean> {
private final Util util; // Any beans that need to be injected into the custom converter
@Autowired // Constructor Injection
public LoadableFooBeanConverter(Util util) {
super(BarBean.class, FooBean.class);
this.util = util;
}
@Override
public FooBean convertTo(final BarBean source, final FooBean destination) {
// Your logic
}
@Override
public BarBean convertFrom(final FooBean source, final BarBean destination) {
// Your logic
}
}
Create the Mapper component and register the custom converter as below:
@Component
@RequiredArgsConstructor // lombok annotation
public class DozerMapper {
@Autowired
private final LoadableFooBeanConverter loadableFooBeanConverter;
@Getter // lombok annotation
private Mapper mapper;
@PostConstruct
public void init() {
this.mapper = DozerBeanMapperBuilder.create()
.withMappingBuilders(BarMappingBuilder.builder().build())
.withCustomConverterWithId("loadableFooBeanConverter", loadableFooBeanConverter)
.build();
}
@Builder // lombok annocation
private static class BarMappingBuilder extends BeanMappingBuilder {
@Override
protected void configure() {
mapping(FooBar.class, FooBarFoo.class)
.fields("fooBean", "barBean", FieldsMappingOptions.customConverterId("loadableFooBeanConverter"));
}
}
}
来源:https://stackoverflow.com/questions/6695884/custom-converter-with-spring-dependency-injection