'Easiest Way for MapStruct to map a default for all properties of an object

Suppose I have a target object

MyObject {
    boolean myBoolean;
    int myInt;
    ...
}

where fields myBoolean and myInt are required (i.e., if you try to call build() on the Builder for MyObject without setting those fields, an error is thrown).

I can't seem to find a simple way to tell MapStruct to set defaults for each field in my object to ensure all required fields have been set, despite trying a number of MapStruct constructs that seem related to this functionality:

  1. According to documentation, NullValuePropertyMappingStrategy is only for update methods.
  2. If I try to set nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT on the @Mapper level, MapStruct won't actually set the default for each field. The generated code looks like (e.g.):

.

Builder target = new Target.builder();
if (source != null) {
    if ( source.isMyBoolean() != null ) {
        target.withMyBoolean( source.isMyBoolean() );
    }
    ...
}
target.build();

In the above the field myBoolean in Source is a Boolean (vs. a boolean). As you can see, if source.isMyBoolean == null then target.withMyBoolean(...) will not be called, causing an error.

The only way I have found to get around this is to specify a NullValueMappingStrategy or a defaultValue on the individual @Mapping level for each required property which is very verbose.

Wondering if anyone knows a better way to accomplish this.



Solution 1:[1]

If your target object has primitives your fields has default value, no ?

As say in the doc NullValueMappingStrategy.RETURN_DEFAULT work on bean, list ... but you are right not on Integer, String, Boolean.

If I have :

public class MyObjectDTO {

  Boolean myBoolean;

  Integer myInt;

  String myString;

  TempObjectDTO tempObjectDTO;
}

public class MyObject {

  Boolean myBoolean;

  Integer myInt;

  String myString;

  TempObject tempObject;
}

After mapping MyObject <--> MyObjectDTO :

  • TempObject/TempObjectDTO has default value
  • all other objects have null value.

To prevent this I have created mapping method for String, Integer, Boolean in the mapper and use a factory because Integer and Boolean doesn't have a default constructor.

Mapper:

@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,//
    uses = { DefaultFactory.class })
public interface MyObjectMapper {

  @Mapping(source = "tempObjectDTO", target = "tempObject")
  MyObject fromDTO(MyObjectDTO myObjectDTO);

  @Mapping(source = "tempObject", target = "tempObjectDTO")
  MyObjectDTO toDTO(MyObject myObject);

  TempObject fromDTO(TempObjectDTO dto);

  TempObjectDTO fromDTO(TempObject tempObject);

  String from(String string);

  Integer from(Integer integer);

  Boolean from(Boolean booleanObject);
}

Factory:

public class DefaultFactory {

  public Integer createInteger() {
    return new Integer(100);
  }

  public Boolean createBoolean() {
    return new Boolean(true);
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 lmoal