# Java Builder

## Basic Mapping

We start by defining two classes, our source class `SimpleEntity` and our destination class `SimpleEntityDisplay`.

```java
public class SimpleEntity {
    private String name;
    private String description;
    private String privateData;

    public SimpleEntity() {
    }

    public SimpleEntity(String name, String description, String privateData) {
        this.name = name;
        this.description = description;
        this.privateData = privateData;
    }

    // Getters and Setters...
}
```

```java
public class SimpleEntityDisplay {
    private String name;
    private String description;

    public SimpleEntityDisplay() {
    }

    // 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.

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("name", "name")
        .mapField("description", "description")
        .build();
```

To instantiate `ShapeShift` we use the `ShapeShiftBuilder` and register our mapper:

```java
ShapeShift shapeShift = new ShapeShiftBuilder()
        .withMapping(mappingDefinition)
        .build();
```

All that's left is to map the `SimpleEntity` instance to the `SimpleEntityDisplay` class.

```java
SimpleEntity simpleEntity = new SimpleEntity("test", "test description", "private data");
SimpleEntityDisplay simpleEntityDisplay = shapeShift.map(simpleEntity, 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:

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

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`.

```kotlin
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(From.class, To.class)
        .mapField("child.value", "childValue")
        .build();
```

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:

{% content-ref url="../features/transformers" %}
[transformers](https://shapeshift.krud.dev/features/transformers)
{% endcontent-ref %}

The `withTransformer` function has 2 options to use transformers. Let's look at the following classes.

```java
public class SimpleEntity {
    private String commaDelimitedString;

    public SimpleEntity() {
    }

    public SimpleEntity(String commaDelimitedString) {
        this.commaDelimitedString = commaDelimitedString;
    }

    // Getters and Setters...
}
```

```java
public class SimpleEntityDisplay {
    private List<String> stringList;

    public SimpleEntityDisplay() {
    }

    // Getters and Setters...
}

```

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

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

All we need to do to use our transformer is to pass it to the `withTransformer` function.

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("commaDelimitedString", "stringList")
        .withTransformer(StringToListMappingTransformer.class)
        .build();
```

{% hint style="info" %}
Transformers must be registered to the `ShapeShift` instance in order to be used. More info about registering transformers is available in the [transformers page](https://shapeshift.krud.dev/features/transformers).
{% endhint %}

{% content-ref url="../features/transformers" %}
[transformers](https://shapeshift.krud.dev/features/transformers)
{% endcontent-ref %}

### Inline Transformer

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.

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("commaDelimitedString", "stringList")
        .withTransformer(context -> context.getOriginalValue() != null 
                ? Arrays.asList(((String) context.getOriginalValue()).split(",")) 
                : null)
        .build();
```

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

{% content-ref url="../features/auto-mapping" %}
[auto-mapping](https://shapeshift.krud.dev/features/auto-mapping)
{% endcontent-ref %}

Auto mapping can be added using the `autoMap` function.&#x20;

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .autoMap(AutoMappingStrategy.BY_NAME)
        .mapField("name", "fullName")
        .build();
```

`autoMap` function receives the desired [auto mapping strategy](https://shapeshift.krud.dev/features/auto-mapping#auto-mapping-strategy). It is possible to add any manual mapping to add/change mapping behavior.

## Mapping Condition

Conditions are used to determine wether a field should be mapped according to certain logic. More info about conditions is available here:

{% content-ref url="../features/conditions" %}
[conditions](https://shapeshift.krud.dev/features/conditions)
{% endcontent-ref %}

Let's look at the following classes.

```java
public class SimpleEntity {
    private String name;

    public SimpleEntity() {
    }

    // Getters and Setters...
}
```

```kotlin
public class SimpleEntityDisplay {
    private String name;

    public SimpleEntityDisplay() {
    }

    // Getters and Setters...
}
```

We want to map the `name` field only if it's not null or blank. The `withCondition` function has 2 options to add conditions. &#x20;

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

```java
public class NotBlankStringCondition implements MappingCondition<String> {
    @Override
    public boolean isValid(@NonNull MappingConditionContext<String> context) {
        return context.getOriginalValue() != null && !context.getOriginalValue().trim().isEmpty();
    }
}
```

We will create our mapper and add the condition.

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("name", "name")
        .withCondition(NotBlankStringCondition.class)
        .build();
```

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

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("name", "name")
        .withCondition(context -> context.getOriginalValue() != null && !((String) context.getOriginalValue()).trim().isEmpty())
        .build();
```

## Decorators

Decorators allow to add additional logic to the mapping operation. More info about conditions is available here:

{% content-ref url="../features/decorators" %}
[decorators](https://shapeshift.krud.dev/features/decorators)
{% endcontent-ref %}

Let's look at the following classes.

```java
public class User {
    private String firstName;
    private String lastName;
    // Getters and Setters...
}
```

```java
public class UserDisplay {
    private String firstName;
    private String lastName;
    private String fullName;
    // Getters and Setters...
}
```

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.

```java
public class UserUserDisplayDecorator implements MappingDecorator<User, UserDisplay> {
    @Override
    public void decorate(@NonNull MappingDecoratorContext<User, UserDisplay> mappingDecoratorContext) {
        User from = mappingDecoratorContext.getFrom();
        UserDisplay to = mappingDecoratorContext.getTo();
        to.setFullName(from.getFirstName() + " " + from.getLastName());
    }
}a
```

And register it to the `ShapeShift` instance.

```java
ShapeShift shapeShift = new ShapeShiftBuilder()
        .withDecorator(User.class, UserDisplay.class, new UserUserDisplayDecorator())
        .build();
```

### Inline Decorators

It is also possible to add the decorator logic inline.

```java
ShapeShift shapeShift = new ShapeShiftBuilder()
        .withDecorator(User.class, UserDisplay.class, mappingDecoratorContext -> {
            User from = mappingDecoratorContext.getFrom();
            UserDisplay to = mappingDecoratorContext.getTo();
            to.setFullName(from.getFirstName() + " " + from.getLastName());
        })
        .build();
```

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

{% content-ref url="../features/object-suppliers" %}
[object-suppliers](https://shapeshift.krud.dev/features/object-suppliers)
{% endcontent-ref %}

## Override Mapping Strategy

The `overrideStrategy` function allows you to override the default mapping strategy configured on the `ShapeShift` instance.&#x20;

```java
MappingDefinition mappingDefinition = new MappingDefinitionBuilder(SimpleEntity.class, SimpleEntityDisplay.class)
        .mapField("name", "name").withMappingStrategy(MappingStrategy.MAP_ALL)
        .build();
```

More info about mapping strategy is available here:

{% content-ref url="../features/mapping-strategy" %}
[mapping-strategy](https://shapeshift.krud.dev/features/mapping-strategy)
{% endcontent-ref %}
