Skip to content

Conversion examples

avurro edited this page Aug 13, 2015 · 2 revisions

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.

1° Scenario

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]

2° Scenario

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.

3° Scenario

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.

Overall

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
Clone this wiki locally