Advanced Mapping Nested fields and multiple targets annotations mapping.
In this guide, we'll review mapping nested fields , as well as defining mappings to multiple targets .
Classes
We start by defining our source and destination classes, and additionally a child class which will be used by both.
Starting with the child class:
Kotlin Java
Copy data class AdvancedChildEntity (
val childName: String
)
Copy public class AdvancedChildEntity {
private String childName;
public String getChildName () {
return childName;
}
public void setChildName ( String childName) {
this . childName = childName;
}
}
Followed by our source class:
Kotlin Java
Copy data class AdvancedEntity (
val name: String ,
val firstChild: AdvancedChildEntity ,
val secondChild: AdvancedChildEntity
)
Copy public class AdvancedEntity {
private String name;
private AdvancedChildEntity firstChild;
private AdvancedChildEntity secondChild;
public String getName () {
return name;
}
public void setName ( String name) {
this . name = name;
}
public AdvancedChildEntity getFirstChild () {
return firstChild;
}
public void setFirstChild ( AdvancedChildEntity firstChild) {
this . firstChild = firstChild;
}
public AdvancedChildEntity getSecondChild () {
return secondChild;
}
public void setSecondChild ( AdvancedChildEntity secondChild) {
this . secondChild = secondChild;
}
}
In this example, we will have two separate destination classes, AdvancedEntityDisplay
and ReducedAdvancedEntityDisplay
.
Kotlin Java
Copy data class AdvancedEntityDisplay (
val name: String = "" ,
val firstChildName: String = "" ,
val secondChildName: String = ""
)
Copy public class AdvancedEntityDisplay {
private String name = "" ;
private String firstChildName = "" ;
private String secondChildName = "" ;
public String getName () {
return name;
}
public void setName ( String name) {
this . name = name;
}
public String getFirstChildName () {
return firstChildName;
}
public void setFirstChildName ( String firstChildName) {
this . firstChildName = firstChildName;
}
public String getSecondChildName () {
return secondChildName;
}
public void setSecondChildName ( String secondChildName) {
this . secondChildName = secondChildName;
}
}
Kotlin Java
Copy data class ReducedAdvancedEntityDisplay (
val name: String = "" ,
val firstChildName: String = ""
)
Copy public class ReducedAdvancedEntityDisplay {
private String name = "" ;
private String firstChildName = "" ;
public String getName () {
return name;
}
public void setName ( String name) {
this . name = name;
}
public String getFirstChildName () {
return firstChildName;
}
public void setFirstChildName ( String firstChildName) {
this . firstChildName = firstChildName;
}
}
Annotations
Let's start adding annotations to the source class. We will define a @DefaultMappingTarget
annotation on the AdvancedEntity
class, which will indicate that all fields annotated with @MappedField
that do not specify a target should be mapped to the AdvancedEntityDisplay
class. Seeing as we have two destinations in this example, we will have to define some of the mapping targets manually.
We'll start by defining a simple @MappedField
on the name
field for both targets. We will also define a @MappedField
annotation on the firstChild
field, which will indicate that it should be mapped to the firstChildName
field on the AdvancedEntityDisplay
class, and repeat the same annotation for secondChild
. To achieve this we will use the mapFrom
and mapTo
parameters. Notice that by doing this, we have extracted the name
field from the AdvancedEntity
class, and mapped it directly to the *ChildName
field on the AdvancedEntityDisplay
class. The ReducedAdvancedEntityDisplay
class will have the same mapping as the AdvancedEntityDisplay
class, but will omit the secondChildName
field;
Kotlin Java
Copy @DefaultMappingTarget (AdvancedEntityDisplay:: class )
data class AdvancedEntity (
@MappedField
@MappedField (target = ReducedAdvancedEntityDisplay:: class )
val name: String ,
@MappedField (mapFrom = "childName" , mapTo = "firstChildName" )
@MappedField (target = ReducedAdvancedEntityDisplay:: class , mapFrom = "childName" , mapTo = "firstChildName" )
val firstChild: AdvancedChildEntity ,
@MappedField (mapFrom = "childName" , mapTo = "secondChildName" )
val secondChild: AdvancedChildEntity
)
Copy @ DefaultMappingTarget ( AdvancedEntityDisplay . class )
public class AdvancedEntity {
@ MappedField
@ MappedField (target = ReducedAdvancedEntityDisplay . class )
private String name;
@ MappedField (mapFrom = "childName" , mapTo = "firstChildName" )
@ MappedField (target = ReducedAdvancedEntityDisplay . class , mapFrom = "childName" , mapTo = "firstChildName" )
private AdvancedChildEntity firstChild;
@ MappedField (mapFrom = "childName" , mapTo = "secondChildName" )
private AdvancedChildEntity secondChild;
// Getters and Setters...
}
Test
Finally, let's write two tests to verify that our mapping is working correctly for both targets
Kotlin Java
Copy @Test
fun `test advanced mapping for AdvancedEntityDisplay` () {
val shapeShift = ShapeShift ()
val advancedEntity = AdvancedEntity (
"test" ,
AdvancedChildEntity ( "first child" ),
AdvancedChildEntity ( "second child" )
)
val result = shapeShift. map < AdvancedEntityDisplay >(advancedEntity)
expectThat (result.name)
. isEqualTo ( "test" )
expectThat (result.firstChildName)
. isEqualTo ( "first child" )
expectThat (result.secondChildName)
. isEqualTo ( "second child" )
}
@Test
fun `test advanced mapping for ReducedAdvancedEntityDisplay` () {
val shapeShift = ShapeShift ()
val advancedEntity = AdvancedEntity (
"test" ,
AdvancedChildEntity ( "first child" ),
AdvancedChildEntity ( "second child" )
)
val result = shapeShift. map < ReducedAdvancedEntityDisplay >(advancedEntity)
expectThat (result.name)
. isEqualTo ( "test" )
expectThat (result.firstChildName)
. isEqualTo ( "first child" )
}
Copy @ Test
public void testAdvancedMappingForAdvancedEntityDisplay() {
ShapeShift shapeShift = new ShapeShiftBuilder() . build ();
AdvancedEntity advancedEntity = new AdvancedEntity() ;
advancedEntity . setName ( "test" );
AdvancedChildEntity firstChild = new AdvancedChildEntity() ;
firstChild . setChildName ( "first child" );
advancedEntity . setFirstChild (firstChild);
AdvancedChildEntity secondChild = new AdvancedChildEntity() ;
secondChild . setChildName ( "second child" );
advancedEntity . setSecondChild (secondChild);
AdvancedEntityDisplay result = shapeShift . map (advancedEntity , AdvancedEntityDisplay . class );
assertEquals( result . getName() , "test" ) ;
assertEquals( result . getFirstChildName() , "first child" ) ;
assertEquals( result . getSecondChildName() , "second child" ) ;
}
@ Test
public void testAdvancedMappingForReducedAdvancedEntityDisplay() {
ShapeShift shapeShift = new ShapeShiftBuilder() . build ();
AdvancedEntity advancedEntity = new AdvancedEntity() ;
advancedEntity . setName ( "test" );
AdvancedChildEntity firstChild = new AdvancedChildEntity() ;
firstChild . setChildName ( "first child" );
advancedEntity . setFirstChild (firstChild);
AdvancedChildEntity secondChild = new AdvancedChildEntity() ;
secondChild . setChildName ( "second child" );
advancedEntity . setSecondChild (secondChild);
ReducedAdvancedEntityDisplay result = shapeShift . map (advancedEntity , ReducedAdvancedEntityDisplay . class );
assertEquals( result . getName() , "test" ) ;
assertEquals( result . getFirstChildName() , "first child" ) ;
}
Full Example
You can check out the full example here .