-
Notifications
You must be signed in to change notification settings - Fork 41
Explicit Conversions
Explicit conversion allows you to define your own control logic and / or processing data belonging to the source fields and assign them to the destination fields.
You can define conversions through the use of methods and you can do it in java, using the @JMapConversion
annotation, in XML using the <conversion>
node and in API through the Conversion
class.
These give the same possibility and use the same parameters but in different format.
IMPORTANT!
- The XML and API conversions have greater visibility of the equivalent annotated. For a specific relation is found first in the XML/API conversion method, if not found, will be done a search of the annotated conversion method if exist.
- The conversion, once satisfied the relationship, replaces the basis mapping of the framework.
- If there are more conversion methods satisfying the relationship, the first found will be considered.
- The code must be written according the javassist specifications (if you are using the default bytecode generator).
The position of the conversion is independent from the configuration location
the conversions can be written in the Destination or Source, regardless the configuration location.
different combinations of configuration are permitted
You can also do a combination with all configuration format, for example: configuration with annotations and conversions in xml or vice versa.
you must always and only specify the names of the fields, also in case of nested mapping
For example: if we have a field in Source mapped with ${destination.nestedDestination}
the from and to parameters will be respectively: "source"
and "nestedDestination"
.
The conversion between two fields is applied only when there is a relationship between them, follows an example of not applied conversion:
class Destination{ class Source{
@JMap
private String id; private String id;
@JMap("sourceField")
private String destinationField; private String sourceField;
private String other; private String other;
@JMapConversion(from={"id"}, to={"other"})
public String conversion(String str){
return str;
}
// getters and setters... // getters and setters...
} }
Assuming to initialize the JMapper class in the following way:
JMapper jmapper = new JMapper<>(Destination.class, Source.class);
relations expressed:
- Source.id
->
Destination.id
- Source.sourceField
->
Destination.destinationField
The conversion instead is defined for the relation:
- Source.id
->
Destination.other
So in this case the conversion will never be applied, the same happens also for the configuration in XML and API format.
After a short overview, we will see what are the configuration parameters common to all types of mapping.
We discuss them at a logical level, for use in detail see the relative section.
The following is a summary table:
Configuration parameter | Description | Default Value |
---|---|---|
name (required) | name of the method | Undefined |
from (optional) | names of the source fields | ALL |
to (optional) | names of the destination fields | ALL |
type (optional) | conversion type | STATIC |
avoidSet (optional) | avoid set method usage | false |
The name is essential to distinguish the conversion methods between their.
The parameters from and to indicate which fields will be part of the conversion.
The from indicates the source, the to indicates the recipients, the default value for each is ALL
which mean that the conversion will be applied to all related fields.
The Type allows you to define the conversion modes and has only two values: STATIC
and DYNAMIC
, it will be explained later.
avoidSet avoids the call to the set method for the destination instance if it's set to true
.
These are the configuration parameters that can be used in all types of mapping, below we will see how to do for each type.
This is an example of configuration in annotation style:
@JMapConversion (from = {"srcField1","srcField2"}, to={"destinationField"}, avoidSet=false, type=Type.STATIC)
The name is not required because is used the conversion method name.
An example in xml format:
<conversion name="conversion" from="srcField1,srcField2" to="destinationField" avoidSet="false" type="STATIC">
configuration in API:
conversion("conversionName")
.from("srcField1","srcField2")
.to("destinationField")
.avoidSet(false)
.type(Type.STATIC)
The generated code is surrounded by a Try-Catch inserted with the aim of managing all the errors generated at runtime, such as NullPointerException
.
The conversion methods can be of two types: STATIC and DYNAMIC, static when is used for a specific relationship, dynamic when the method's body change according the relationship that must be satisfied.
The placeholders that can be used in all configuration types are:
Placeholder | Description |
---|---|
${source} | source reference |
${destination} | destination reference |
${source.type} | source type |
${destination.type} | destination type |
${source.name} | source name |
${destination.name} | destination name |
${destination.get} | destination get method name |
${destination.set} | destination set method name |
${source.get} | source get method name |
${source.set} | source set method name |
A conversion is called static when its body does not change with the defined relations.
Suppose we have two classes: Destination and Source, both with 3 fields of type String: d1, d2 and d3 for Destination and s1, s2, and s3 for Source and that you have configured s1 with d1, d2 with s2 and d3 with s3.
We want to define a conversion to be applied to all relationships, then the method will be defined (e.g. in annotation):
@JMapConversion(from={"s1","s2","s3"}, to={"d1","d2","d3"})
public String conversion(String source){
return source + " converted";
}
There are some important requirements to respect in the implementation of the method (valid only for annotation):
- the input field to the method must be the same type of the source fields
- in case of definition of two input, the first from the left must be the same type of destination, the second the same type of source:
@JMapConversion(from={"s1","s2","s3"}, to={"d1","d2","d3"})
public String conversion(String destination, String source){
return destination + source + " converted";
}
- the output field to the method must be the same type of destination fields
Assuming that this method is defined in the Destination, the mapping generated at runtime will be as follows:
destination.setD1(destination.conversion(source.getS1()));
destination.setD2(destination.conversion(source.getS2()));
destination.setD3(destination.conversion(source.getS3()));
This conversion is the most common and also the most useful, allows to pool a manipulation that can affect more data.
In case there are any static methods with the same name, will be considered only the first one that meets the requirements.
Consists in the definition of the conversion node, whose value is the body of the method to create.
To refer to the source field and destination field you must use the following placeholders:
- ${source} to refer to the source field
- ${destination} to refer to the destination field
Example:
<conversion name="conversion" from="anInteger" to="aString">
return ${source}.toString();
</conversion>
Method created at runtime:
public String conversion(Integer source){
return source.toString();
}
Mapping generated:
destination.setAString(conversion(source.getAnInteger()));<br>
If you want to act even on the destination, just use the placeholder: ${destination}
.
<conversion name="conversion" from="sourceField" to="destinationField">
return ${destination}+" "+${source}+" converted";
</conversion>
Method created at runtime:
public String conversion(String destination, Integer source){
return destination +" "+ source +" converted";
}
Mapping generated:
destination.setAString(conversion(destination.getAString(),source.getAnInteger()));
The body definition in this case is equal to XML format:
conversion("conversionName")
.from("sourceField")
.to("destinationField")
.body("return ${source}.toString();");
For dynamic conversion we means a method whose body is adapted to every relationship.
The conversion method defined is always one, but at runtime will be created a number of conversions equal to the number of relations.
The dynamic conversion allows to pool the basic logic varying only some values.
There are some important requirements to respect in the implementation of the method (valid only for annotation):
- The method must be public static
- no input parameters
- must return a string containing the dynamic mapping
Example (in annotation):
@JMapConversion(from={"s1,s2,s3"}, to={"d1,d2,d3"}, type=Type.DYNAMIC)
public static String conversion(){
return "return \"${destination.name} ${source.name}\";";
}
Method created at runtime:
public String fromS1ToD1(){
return "d1 s1";
}
public String fromS2ToD2(){
return "d2 s2";
}
public String fromS3ToD3(){
return "d3 s3";
}
Generated mapping:
destination.setD1(fromS1toD1());
destination.setD2(fromS2toD2());
destination.setD3(fromS3toD3());
As you can see, the methods do not take input data because destination and source aren't referenced with the placeholder ${source}
and ${destination}
.
Below an example of the use of destination and source references:
@JMapConversion(from={"anInteger"}, to={"aString"}, type=Type.DYNAMIC)
Public static String conversion(){
return "${destination.type} result = ${source} == 2?\"${source.name}\":\"${destination.name}\";"
+ "return result + ${destination};";
}
Method created at runtime:
public String FROManIntegerTOaString(String destination, Integer source){
String result = source == 2? "anInteger":"aString";
return result + destination;
}
Generated mapping:
dest.setAString(fromAnIntegertoAString(dest.getAString(),source.getAnInteger()));
In XML format:
<conversion name="conversion" from="anInteger" to="aString" type="DYNAMIC">
${destination.type} result = ${source} == 2?"${source.name}":"${destination.name}";
return result + ${destination};
</conversion>
API version:
conversion("conversionName")
.from("anInteger")
.to("aString")
.type(Type.DYNAMIC)
.body("${destination.type} result = ${source} == 2?\"${source.name}\":\"${destination.name}\";"+
"return result + ${destination};");
© 2016 Alessandro Vurro
- Home
- How to map
- Relations
- Conversions
- creation/enrichment
- XML
- Annotation
- API
- Configurations
- Utilities
- Examples
- Articles
- More information
- Performance tests
- Release Notes