publicclassSimpleEntityDisplay{privateString name;privateString description;publicSimpleEntityDisplay(){} // Getters and Setters...}
We can now create a simple mapper. In this example, we want to map the name and description fields of SimpleEntity to the name and description fields of the SimpleEntityDisplay class, but not the privateData field.
To instantiate ShapeShift we use the ShapeShiftBuilder and register our mapper:
All that's left is to map the SimpleEntity instance to the SimpleEntityDisplay class.
Mapping Fields
In the example above we did basic mapping between fields. But what if we want to map from/to deep fields of child classes?
In order to access child classes we can use the full path of a field. Let's look at the following example:
We want to map the value field in Child class inside the From class to the childValue field in the To class. We will use the full path of value which is child.value.
The full path is supported in both source and destination fields, it also supports multi level depth (e.g. x.y.z).
Transformers
Field transformers are a way to transform a field from one type to another when mapping it to a destination class. More about the ins-and-outs of transformers is available here:
The withTransformer function has 2 options to use transformers. Let's look at the following classes.
We want to map the commaDelimitedString field to the stringList field and change the field type from String to List<String> while doing so. To accomplish that we will use a transformer.
Class Transformer
Our first option is to create a transformer class, StringToListMappingTransformer;
All we need to do to use our transformer is to pass it to the withTransformer function.
Transformers must be registered to the ShapeShift instance in order to be used. More info about registering transformers is available in the transformers page.
Our second option is to use an inline transformer. When we don't need to reuse a transformer we can just add its logic to the builder.
Auto Mapping
Auto mapping is used to reduce the amount of boiler-place code required to configure mapping between two classes. More info about auto mapping is available here:
We want to map the name field only if it's not null or blank. The withCondition function has 2 options to add conditions.
Class Condition
Our first option is to create a condition class. The condition receives context with the original value of the field and checks that it is not null or blank.
We will create our mapper and add the condition.
Inline Condition
Our second option is to use an inline condition. When we don't need to reuse a condition we can just add its logic to the builder.
Decorators
Decorators allow to add additional logic to the mapping operation. More info about conditions is available here:
We want to merge the firstName and lastName fields to the fullName field in addition to mapping them to their respectable fields.
Decorators can be added inline or as a separate class.
Class Decorators
To create a decorator class implement the MappingDecorator interface.
And register it to the ShapeShift instance.
Inline Decorators
It is also possible to add the decorator logic inline.
Object Suppliers
Due to the fact that ShapeShift uses reflection behind the scenes, destination classes need a no arg constructor. But in some cases you have no control over the destination classes and cannot modify them to add a no arg constructor. This is where Object Suppliers comes into play, you can register object suppliers to the ShapeShift instance to add your own logic for instance generation.
More info about Object Suppliers is available here:
public class From {
private Child child = new Child();
// Getters and Setters...
class Child {
private String value;
// Getters and Setters...
}
}
public class To {
private String childValue;
// Getters and Setters...
}
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(From.class, To.class)
.mapField("child.value", "childValue")
.build();
public class SimpleEntity {
private String commaDelimitedString;
public SimpleEntity() {
}
public SimpleEntity(String commaDelimitedString) {
this.commaDelimitedString = commaDelimitedString;
}
// Getters and Setters...
}
public class SimpleEntityDisplay {
private List<String> stringList;
public SimpleEntityDisplay() {
}
// Getters and Setters...
}
public class StringToListMappingTransformer implements MappingTransformer<String, List<String>> {
@Nullable
@Override
public List<String> transform(@NonNull MappingTransformerContext<? extends String> context) {
return context.getOriginalValue() != null
? Arrays.asList(context.getOriginalValue().split(","))
: null;
}
}
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
.mapField("commaDelimitedString", "stringList")
.withTransformer(StringToListMappingTransformer.class)
.build();