Comment on page
Annotations
Annotations based usage of the ShapeShift library.
We start by defining two classes, our source class
SimpleEntity
and our destination class SimpleEntityDisplay
.Kotlin
Java
data class SimpleEntity(
val name: String,
val description: String,
val privateData: String
)
public class SimpleEntity {
private String name;
private String description;
private String privateData;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPrivateData() {
return privateData;
}
public void setPrivateData(String privateData) {
this.privateData = privateData;
}
}
Kotlin
Java
data class SimpleEntityDisplay(
val name: String = "",
val description: String = ""
)
public class SimpleEntityDisplay {
private String name = "";
private String description = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
We can now start adding our annotations to the
SimpleEntity
class. In this example, we want to map the name
and description
fields to the name
and description
fields of the SimpleEntityDisplay
class, but not the privateData
field.To achieve this, we will use the @MappedField annotation on both of these fields. Additionally, we will define
@DefaultMappingTarget
on the SimpleEntity
class, which will indicate that all fields annotated with @MappedField
that do not specify a target should be mapped to the SimpleEntityDisplay
class.Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField
val name: String,
@MappedField
val description: String,
val privateData: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField
private String name;
@MappedField
private String description;
private String privateData;
// Getters and Setters...
}
@DefaultMappingTarget
on a class, indicates that all fields annotated with @MappedField
that do not specify a target should be mapped to this class by default.The mapping target comes into play when you want to map a single source to multiple destinations. The
target
attribute is used to indicate to which class the field should be mapped. If no target is specified the target will be determined by the @DefaultMappingTarget
on the class.Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField
@MappedField(target = SimpleEntityExport::class)
val name: String,
@MappedField
val description: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField
@MappedField(target = SimpleEntityExport.class)
private String name;
@MappedField
private String description;
// Getters and Setters...
}
In the above code name is mapped once to the
SimpleEntityDisplay
class using the default mapping target, and once to the SimpleEntityExport
class using the target
attribute.Kotlin
Java
data class SimpleEntityDisplay(
val name: String = "",
val description: String = ""
)
public class SimpleEntityDisplay {
private String name = "";
private String description = "";
// Getters and Setters...
}
Kotlin
Java
data class SimpleEntityExport(
val name: String = ""
)
public class SimpleEntityExport {
private String name = "";
// Getters and Setters...
}
By default each
@MappedField
is mapped to a field with the same name in the target class. To change it use the mapTo
value. For example:Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField(mapTo = "fullName")
val name: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField(mapTo = "fullName")
private String name;
// Getters and Setters...
}
Kotlin
Java
data class SimpleEntityDisplay(
val fullName: String = ""
)
public class SimpleEntityDisplay {
private String fullName = "";
// Getters and Setters...
}
The field name to map the value from.
When
mapFrom
is used at the field level, it allows for mapping of nested values.Kotlin
Java
@DefaultMappingTarget(AdvancedEntityDisplay::class)
data class AdvancedEntity(
// This field will be mapped to the "firstChildName" field in the default target class
@MappedField(mapFrom = "childName", mapTo = "firstChildName")
val firstChild: AdvancedChildEntity,
// This field will be mapped to the "secondChildName" field in the default target class
@MappedField(mapFrom = "childName", mapTo = "secondChildName")
val secondChild: AdvancedChildEntity
)
@DefaultMappingTarget(AdvancedEntityDisplay.class)
public class AdvancedEntity {
// This field will be mapped to the "firstChildName" field in the default target class
@MappedField(mapFrom = "childName", mapTo = "firstChildName")
private AdvancedChildEntity firstChild;
// This field will be mapped to the "secondChildName" field in the default target class
@MappedField(mapFrom = "childName", mapTo = "secondChildName")
private AdvancedChildEntity secondChild;
// Getters and Setters...
}
As you can see above, we use the
mapFrom
attribute to access the childName
field in AdvancedChildEntity
.Kotlin
Java
data class AdvancedChildEntity(
val childName: String
)
public class AdvancedChildEntity {
private String childName;
// Getters and Setters...
}
And we use the
mapTo
attribute to map the values to the appropriate fields in AdvancedEntityDisplay.
Kotlin
Java
data class AdvancedEntityDisplay(
val firstChildName: String = "",
val secondChildName: String = ""
)
public class AdvancedEntityDisplay {
private String firstChildName = "";
private String secondChildName = "";
// Getters and Setters...
}
The
@MappedField
annotation can also be used at the type level. When used at the type level, the mapFrom
attribute is required to indicate the name of the field to use, if left empty an exception will be thrown.Kotlin
Java
@MappedField(target = SimpleEntityDisplay::class, mapFrom = "firstName")
@MappedField(target = SimpleEntityDisplay::class, mapFrom = "lastName")
data class SimpleEntity(
val firstName: String,
val lastName: String,
)
@MappedField(target = SimpleEntityDisplay.class, mapFrom = "firstName")
@MappedField(target = SimpleEntityDisplay.class, mapFrom = "lastName")
public class SimpleEntity {
private String firstName;
private String lastName;
// Getters and Setters...
}
Kotlin
Java
data class SimpleEntityDisplay(
val firstName: String = "",
val lastName: String = ""
)
public class SimpleEntityDisplay {
private String firstName = "";
private String lastName = "";
// Getters and Setters...
}
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:
To configure a transformer for a field use the
transformer
attribute. The transformer
attribute receives the transformer's class.Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField(transformer = StringToListMappingTransformer::class, mapTo = "stringList")
val commaDelimitedString: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField(transformer = StringToListMappingTransformer.class, mapTo = "stringList")
private String commaDelimitedString;
// Getters and Setters...
}
Kotlin
Java
data class SimpleEntityDisplay(
val stringList: List<String> = emptyList()
)
public class SimpleEntityDisplay {
private List<String> stringList = new ArrayList<>();
// Getters and Setters...
}
Transformers must be registered to the
ShapeShift
instance in order to be used. More info about registering transformers is available in the transformers page.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:
Auto mapping can be added using the
@AutoMapping
annotation.Kotlin
Java
@AutoMapping(SimpleEntityDisplay::class, strategy = AutoMappingStrategy.BY_NAME)
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
val id: String,
val name: String,
val birthDate: Date,
val email: String,
val telephone: String
)
@AutoMapping(target = SimpleEntityDisplay.class, strategy = AutoMappingStrategy.BY_NAME)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
private String id;
private String name;
private Date birthDate;
private String email;
private String telephone;
// Getters and Setters...
}
The
@AutoMapping
annotation has two attributes:- 1.
target
- If no target is added then the auto mapping will be configured to any target class. It is possible to add multiple@AutoMapping
annotation for multiple target classes. - 2.
Conditions are used to determine wether a field should be mapped according to certain logic. More info about conditions is available here:
A condition can be added to annotation mapping using the
condition
attribute.Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField(condition = NotBlankStringCondition::class)
val name: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField(condition = NotBlankStringCondition.class)
private String name;
// Getters and Setters...
}
We mapped the name field and added a condition for the mapping.
Kotlin
Java
data class SimpleEntityDisplay(
val name: String = ""
)
public class SimpleEntityDisplay {
private String name = "";
// Getters and Setters...
}
The condition receives context with the original value of the field and checks that it is not null or blank.
Kotlin
Java
class NotBlankStringCondition : MappingCondition<String> {
override fun isValid(context: MappingConditionContext<String>): Boolean {
return !context.originalValue.isNullOrBlank()
}
}
public class NotBlankStringCondition implements MappingCondition<String> {
@Override
public boolean isValid(@NonNull MappingConditionContext<String> context) {
return context.getOriginalValue() != null && !context.getOriginalValue().trim().isEmpty();
}
}
The
overrideMappingStrategy
attribute allows you to override the default mapping strategy configured on the ShapeShift
instance. Kotlin
Java
@DefaultMappingTarget(SimpleEntityDisplay::class)
data class SimpleEntity(
@MappedField(overrideMappingStrategy = MappingStrategy.MAP_ALL)
val name: String
)
@DefaultMappingTarget(SimpleEntityDisplay.class)
public class SimpleEntity {
@MappedField(overrideMappingStrategy = MappingStrategy.MAP_ALL)
private String name;
// Getters and Setters...
}
More info about mapping strategy is available here:
Last modified 1yr ago