# Advanced 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:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
data class AdvancedChildEntity(
    val childName: String
)
```

{% endtab %}

{% tab title="Java" %}

```java
public class AdvancedChildEntity {
    private String childName;

    public String getChildName() {
        return childName;
    }

    public void setChildName(String childName) {
        this.childName = childName;
    }
}
```

{% endtab %}
{% endtabs %}

Followed by our source class:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
data class AdvancedEntity(
    val name: String,
    val firstChild: AdvancedChildEntity,
    val secondChild: AdvancedChildEntity
)
```

{% endtab %}

{% tab title="Java" %}

```java
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;
    }
}
```

{% endtab %}
{% endtabs %}

In this example, we will have two separate destination classes, `AdvancedEntityDisplay` and `ReducedAdvancedEntityDisplay`.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
data class AdvancedEntityDisplay(
    val name: String = "",
    val firstChildName: String = "",
    val secondChildName: String = ""
)
```

{% endtab %}

{% tab title="Java" %}

```java
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;
    }
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
data class ReducedAdvancedEntityDisplay(
    val name: String = "",
    val firstChildName: String = ""
)
```

{% endtab %}

{% tab title="Java" %}

```java
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;
    }
}

```

{% endtab %}
{% endtabs %}

## 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;

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
@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
)
```

{% endtab %}

{% tab title="Java" %}

```java
@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...
}
```

{% endtab %}
{% endtabs %}

## Test

Finally, let's write two tests to verify that our mapping is working correctly for both targets

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
@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")
}
```

{% endtab %}

{% tab title="Java" %}

```java
@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");
}
```

{% endtab %}
{% endtabs %}

## Full Example

You can check out the full example [here](https://github.com/krud-dev/shapeshift/tree/master/example/kotlin/advanced-mapping).
