# 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).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shapeshift.krud.dev/guides/advanced-mapping.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
