-
Notifications
You must be signed in to change notification settings - Fork 41
Conversion examples
The dynamic conversion opens interesting scenarios. Allows you to going in introspection avoiding the use of Reflection, an advantage not only in performance but also in code readability. Furthermore, the possibility to outsource the xml, permits to make changes without touch the code, thus greatly increasing the potential of the framework.
This example shows the use of static conversions. We want transform Strings to Dates.
@JGlobalMap
class Dates { class Strings{
Date startDate; String startDate;
Date endDate; String endDate;
// getters and setters.. // getters and setters..
} }
XML configuration:
<jmapper>
<class name="it.jmapper.bean.Strings">
<!-- in this case we use default values -->
<conversion name="toDate">
return new java.text.SimpleDateFormat("dd/MM/yyyy").parse(${source});
</conversion>
</class>
</jmapper>
In this example we use annotated configuration and conversion in xml format.
Method created at runtime:
public Date toDate(String source){
return new java.text.SimpleDateFormat("dd/MM/yyyy").parse(source);
}
mapping generated:
destination.setStartDate(toDate(source.getStartDate()));
destination.setEndDate(toDate(source.getEndDate()));
example code:
JMapper<Dates, Strings> mapper = new JMapper<>(Dates.class, Strings.class);
Dates destination = mapper.getDestination(new Strings("01/01/2012", "01/01/2013"));
System.out.println(destination);
output:
Dates [startDate=Tue Jan 01 00:00:00 CET 2013, endDate=Wed Jan 01 00:00:00 CET 2014]
We have a properties file that we want to load in a bean.
properties file:
author = Alessandro Vurro
framework = JMapper
version = 1.1.0
label = dynamic conversion test
java beans:
@JGlobalMap("properties")
class Destination{ class Source{
private String author; private Properties properties;
private String framework;
private String version; @JMapConversion(from={"properties"}, type=Type.DYNAMIC)
private String label; public static String conversion(){
return "return (String) ${source}.get(\"${destination.name}\");";
}
// getters and setters... // getter and setter...
} }
@JMap allows you to configure a field with only another and not simultaneously with more fields.
For this reason we have configured the Destination with JGlobalMap in direction to the Source field.
Methods created at runtime:
public String fromPropertiestoAuthor(Properties source){
return source.get("author");
}
public String fromPropertiestoFramework(Properties source){
return source.get("framework");
}
public String fromPropertiestoVersion(Properties source){
return source.get("version");
}
public String fromPropertiestoAuthor(Properties source){
return source.get("label");
}
mapping generated:
destination.setAuthor(fromPropertiestoAuthor(source.getProperties()));
destination.setFramework(fromPropertiestoFramework(source.getProperties()));
destination.setVersion(fromPropertiestoVersion(source.getProperties()));
destination.setLabel(fromPropertiestoLabel(source.getProperties()));
example code:
JMapper<Destination,Source> mapper = new JMapper<>(Destination.class, Source.class);
Destination destination = mapper.getDestination(new Source(properties));
System.out.println(destination);
output:
Destination:
author = Alessandro Vurro
framework = JMapper
version = 1.1.0
label = dynamic conversion test
In the case of addition or removal of properties from the file, just add or remove the field from Destination class.
We have a HashMap that has the pair <"name field", value field> and a bean with different fields, we want to do the following:
- load bean from HashMap
- load HashMap from bean
The classes are:
class Destination{ class Source{
private String id; private HashMap<String, Object> map;
private Integer quantity;
private Date purchase;
// getters and setters... // getter and setter...
} }
XML configuration:
<jmapper>
<class name="com.application.Destination">
<global>
<value name="map"/>
<classes>
<class name="com.application.Source"/>
</classes>
</global>
<conversion name="fromMapToAll" from="map" type="DYNAMIC">
return (${destination.type}) ${source}.get("${destination.name}");
</conversion>
<conversion name="fromAllToMap" to="map" type="DYNAMIC">
${destination}.put("${source.name}",${source});
return ${destination};
</conversion>
</class>
</jmapper>
Methods generated at runtime:
public String fromMaptoId(HashMap source){
return (String) source.get("id");
}
public Integer fromMaptoQuantity(HashMap source){
return (Integer) source.get("quantity");
}
public Date fromMaptoPurchase(HashMap source){
return (Date) source.get("purchase");
}
public String fromPropertiestoAuthor(Properties source){
return source.get("label");
}
public HashMap fromIdtoMap(HashMap destination, String source){
destination.put("id",source);
return destination;
}
public HashMap fromQuantitytoMap(HashMap destination, Integer source){
destination.put("quantity",source);
return destination;
}
public HashMap fromPurchasetoMap(HashMap destination, Date source){
destination.put("purchase",source);
return destination;
}
So in case we want to fill the bean starting from HashMap the mapping used will be:
destination.setId(fromMaptoId(source.getMap()));
destination.setQuantity(fromMaptoQuantity(source.getMap()));
destination.setPurchase(fromMaptoPurchase(source.getMap()));
Instead, the mapping used to populate the HashMap from bean:
destination.setMap(fromIdtoMap(destination.getMap(),source.getId()));
destination.setMap(fromQuantitytoMap(destination.getMap(),source.getQuantity()));
destination.setMap(fromPurchasetoMap(destination.getMap(),source.getPurchase()));
example code:
HashMap<String, Object> map = new HashMap<>();
map.put("id", "JMapper Framework v.1.1.0");
map.put("quantity", 10);
map.put("purchase", new Date());
RelationalJMapper<Destination> mapper;
mapper = new RelationalJMapper<>(Destination.class,"xml/dynamicConversion.xml");
Source source = new Source(map);
Destination manyToOne = mapper.manyToOne(source);
System.out.println(manyToOne);
Source empty = new Source(new HashMap<String, Object>());
Source oneToMany = mapper.oneToMany(empty,manyToOne);
System.out.println(oneToMany);
output:
Destination:
id = JMapper Framework v.1.1.0
quantity = 10
purchase = Tue Dec 11 15:41:06 CET 2012
Source:
map = {purchase=Tue Dec 11 15:41:06 CET 2012, quantity=10, id=JMapper Framework v.1.1.0}
In this example we use RelationalJMapper, as you can see in the oneToMany example we pass as input an empty destination instance (Source class in this case become a destination), because the conversion method uses a reference to destination.
Despite the potential of dynamic conversion are so high, the performance isn't affected, since the code continues to be generated at runtime and therefore equivalent to the static code, also increasing advantages such as:
- reducing the amount of code -> increase the readability
- development simplified -> easier maintenance
© 2016 Alessandro Vurro
- Home
- How to map
- Relations
- Conversions
- creation/enrichment
- XML
- Annotation
- API
- Configurations
- Utilities
- Examples
- Articles
- More information
- Performance tests
- Release Notes