You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Sergey Zhemzhitsky (Issue Comment Edited) (JIRA)" <ji...@apache.org> on 2012/03/22 13:48:22 UTC
[jira] [Issue Comment Edited] (CAMEL-5031) Dozer Type Conversion
Does Not Work With Context Based Mappings (map-id)
[ https://issues.apache.org/jira/browse/CAMEL-5031?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13235545#comment-13235545 ]
Sergey Zhemzhitsky edited comment on CAMEL-5031 at 3/22/12 12:48 PM:
---------------------------------------------------------------------
Hi guys,
May be you can find it quite useful, but we were able to workaround such a limitation by create our own converter
{code:java}
public class DozerTypeConverter implements TypeConverter {
public static final String MAP_ID_PROP = "DozerMapID";
private DozerBeanMapper mapper;
public DozerTypeConverter(DozerBeanMapper mapper) {
this.mapper = mapper;
}
public <T> T convertTo(Class<T> type, Object value) {
return convertTo(type, value, null);
}
public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
return convertTo(type, value, exchange.getProperty(MAP_ID_PROP, null, String.class));
}
public <T> T mandatoryConvertTo(Class<T> type, Object value) throws NoTypeConversionAvailableException {
return convertTo(type, value, null);
}
public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {
return convertTo(type, value, exchange.getProperty(MAP_ID_PROP, null, String.class));
}
private <T> T convertTo(Class<T> type, Object value, String mapId) {
if(mapId != null) {
return mapper.map(value, type, mapId);
}
return mapper.map(value, type);
}
}
{code}
Here is how the camel route looks like
{code:xml}
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="startRoute">
<from uri="direct://start" />
<setProperty propertyName="DozerMapID">
<constant>Type2Map</constant>
</setProperty>
<convertBodyTo type="java.util.Map"/>
<to uri="mock://complete"/>
</route>
</camelContext>
{code}
and mapping file
{code:xml}
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
<mapping map-id="Type2Map">
<class-a>org.foo.bar.dozer.DozerTypeConverterTest$Type</class-a>
<class-b>java.util.HashMap</class-b>
<field>
<a>p1</a>
<b key="P1">this</b>
</field>
<field>
<a>p2</a>
<b key="P2">this</b>
</field>
</mapping>
</mappings>
{code}
We also had to modify DozerTypeConverterLoader to create our converter instead of the camel's one.
{code:java}
public class DozerTypeConverterLoader implements InitializingBean, CamelContextAware {
private final Logger logger = LoggerFactory.getLogger(getClass());
private DozerBeanMapper mapper;
private CamelContext camelContext;
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(mapper, "mapper: null");
Assert.notNull(mapper, "camelContext: null");
TypeConverterRegistry registry = getTypeConverterRegistry();
load(registry);
}
public void load(TypeConverterRegistry registry) throws Exception {
List<ClassMap> all = loadMappings(camelContext, mapper);
registerClassMaps(registry, mapper, all);
}
private void registerClassMaps(TypeConverterRegistry registry, DozerBeanMapper dozer, List<ClassMap> all) {
DozerTypeConverter converter = new DozerTypeConverter(dozer);
for (ClassMap map : all) {
if(logger.isInfoEnabled()) {
logger.info("Added {} -> {} as type converter to: {}",
new Object[]{map.getSrcClassName(), map.getDestClassName(), registry});
}
registry.addTypeConverter(map.getSrcClassToMap(), map.getDestClassToMap(), converter);
registry.addTypeConverter(map.getDestClassToMap(), map.getSrcClassToMap(), converter);
}
}
private List<ClassMap> loadMappings(CamelContext camelContext, DozerBeanMapper mapper) {
List<ClassMap> answer = new ArrayList<ClassMap>();
// load the class map using the class resolver so we can load from classpath in OSGi
MappingFileReader reader = new MappingFileReader(XMLParserFactory.getInstance());
List<String> mappingFiles = mapper.getMappingFiles();
if (mappingFiles == null) {
return Collections.emptyList();
}
for (String name : mappingFiles) {
URL url = camelContext.getClassResolver().loadResourceAsURL(name);
MappingFileData data = reader.read(url);
answer.addAll(data.getClassMaps());
}
return answer;
}
@Override
public CamelContext getCamelContext() {
return camelContext;
}
@Override
public void setCamelContext(CamelContext camelContext) {
this.camelContext = camelContext;
}
private TypeConverterRegistry getTypeConverterRegistry() throws Exception {
TypeConverterRegistry registry = camelContext.getTypeConverterRegistry();
if(registry == null) {
TypeConverter converter = camelContext.getTypeConverter();
if (converter != null) {
Method method = converter.getClass().getMethod("getRegistry");
registry = (TypeConverterRegistry) method.invoke(converter);
}
}
return registry;
}
public void setMapper(DozerBeanMapper mapper) {
this.mapper = mapper;
}
}
{code}
Unfortunately the codebase is for camel 2.4, so there are some workarounds for CAMEL-3143 (Take a look at getTypeConverterRegistry method)
was (Author: szhemzhitsky):
Hi guys,
May be you can find it quite useful, but we were able to workaround such a limitation by create our own converter
{code:java}
public class DozerTypeConverter implements TypeConverter {
public static final String MAP_ID_PROP = "DozerMapID";
private DozerBeanMapper mapper;
public DozerTypeConverter(DozerBeanMapper mapper) {
this.mapper = mapper;
}
public <T> T convertTo(Class<T> type, Object value) {
return convertTo(type, value, null);
}
public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
return convertTo(type, value, exchange.getProperty(MAP_ID_PROP, null, String.class));
}
public <T> T mandatoryConvertTo(Class<T> type, Object value) throws NoTypeConversionAvailableException {
return convertTo(type, value, null);
}
public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {
return convertTo(type, value, exchange.getProperty(MAP_ID_PROP, null, String.class));
}
private <T> T convertTo(Class<T> type, Object value, String mapId) {
if(mapId != null) {
return mapper.map(value, type, mapId);
}
return mapper.map(value, type);
}
}
{code}
Here is how the camel route looks like
{code:xml}
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="startRoute">
<from uri="direct://start" />
<setProperty propertyName="DozerMapID">
<constant>Type2Map</constant>
</setProperty>
<convertBodyTo type="java.util.Map"/>
<to uri="mock://complete"/>
</route>
</camelContext>
{code}
and mapping file
{code:xml}
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
<mapping map-id="Type2Map">
<class-a>ru.troika.cto.stdint.esb.dozer.DozerTypeConverterTest$Type</class-a>
<class-b>java.util.HashMap</class-b>
<field>
<a>p1</a>
<b key="P1">this</b>
</field>
<field>
<a>p2</a>
<b key="P2">this</b>
</field>
</mapping>
</mappings>
{code}
We also had to modify DozerTypeConverterLoader to create our converter instead of the camel's one.
{code:java}
public class DozerTypeConverterLoader implements InitializingBean, CamelContextAware {
private final Logger logger = LoggerFactory.getLogger(getClass());
private DozerBeanMapper mapper;
private CamelContext camelContext;
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(mapper, "mapper: null");
Assert.notNull(mapper, "camelContext: null");
TypeConverterRegistry registry = getTypeConverterRegistry();
load(registry);
}
public void load(TypeConverterRegistry registry) throws Exception {
List<ClassMap> all = loadMappings(camelContext, mapper);
registerClassMaps(registry, mapper, all);
}
private void registerClassMaps(TypeConverterRegistry registry, DozerBeanMapper dozer, List<ClassMap> all) {
DozerTypeConverter converter = new DozerTypeConverter(dozer);
for (ClassMap map : all) {
if(logger.isInfoEnabled()) {
logger.info("Added {} -> {} as type converter to: {}",
new Object[]{map.getSrcClassName(), map.getDestClassName(), registry});
}
registry.addTypeConverter(map.getSrcClassToMap(), map.getDestClassToMap(), converter);
registry.addTypeConverter(map.getDestClassToMap(), map.getSrcClassToMap(), converter);
}
}
private List<ClassMap> loadMappings(CamelContext camelContext, DozerBeanMapper mapper) {
List<ClassMap> answer = new ArrayList<ClassMap>();
// load the class map using the class resolver so we can load from classpath in OSGi
MappingFileReader reader = new MappingFileReader(XMLParserFactory.getInstance());
List<String> mappingFiles = mapper.getMappingFiles();
if (mappingFiles == null) {
return Collections.emptyList();
}
for (String name : mappingFiles) {
URL url = camelContext.getClassResolver().loadResourceAsURL(name);
MappingFileData data = reader.read(url);
answer.addAll(data.getClassMaps());
}
return answer;
}
@Override
public CamelContext getCamelContext() {
return camelContext;
}
@Override
public void setCamelContext(CamelContext camelContext) {
this.camelContext = camelContext;
}
private TypeConverterRegistry getTypeConverterRegistry() throws Exception {
TypeConverterRegistry registry = camelContext.getTypeConverterRegistry();
if(registry == null) {
TypeConverter converter = camelContext.getTypeConverter();
if (converter != null) {
Method method = converter.getClass().getMethod("getRegistry");
registry = (TypeConverterRegistry) method.invoke(converter);
}
}
return registry;
}
public void setMapper(DozerBeanMapper mapper) {
this.mapper = mapper;
}
}
{code}
Unfortunately the codebase is for camel 2.4, so there are some workarounds for CAMEL-3143 (Take a look at getTypeConverterRegistry method)
> Dozer Type Conversion Does Not Work With Context Based Mappings (map-id)
> ------------------------------------------------------------------------
>
> Key: CAMEL-5031
> URL: https://issues.apache.org/jira/browse/CAMEL-5031
> Project: Camel
> Issue Type: Improvement
> Components: bean-integration, camel-core
> Affects Versions: 2.6.0, 2.9.0
> Reporter: Andre Piwoni
> Priority: Minor
>
> DozerTypeConverter utilizes DozerBeanMappper's method map(Object source, Class<T> destinationClass) to convert objects. Unfortunately, this does not work for Dozer's context based mapping with map-id because it requires call to DozerBeanMappper.map(Object source, Class<T> destinationClass, String mapId).
> Example below does not work without map-id, which is actually required for this type of mapping (see http://dozer.sourceforge.net/documentation/faq.html#complex-to-map)
> <mapping map-id="myMapping">
> <class-a>x.y.z.ComplexType</class-a>
> <class-b>java.util.Map</class-b>
> <field copy-by-reference="true">
> <a>complexTypeField</a>
> <b key="complexTypeFieldKeyName">this</b>
> </field>
> ...
> </mapping>
> DozerTypeConverterLoader has access to ClassMap and its map-id, if any, in order to construct a lookup for map-id for a given conversion pair. This is tricky, however, since there can be multiple mappings with different ids for the same conversion pair.
> Interfaces for Dozer and Camel Conversion may not be fully compatible but it would be great if at least limitations can be stated in documentation.
> Regards,
> Andre Piwoni
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira