'Mapstruct target creation

How does mapstruct decides between the following approaches:

  • Get all parameters using getters of source and then call constructor of target to create the mapping.

  • Call constructor of target with all null parameters, then set each of them using setters.

    Target target(Source source) {
      if ( source == null ) {
          return null;
      }
    
      String a = null;
      String b = null;
      String c = null;
    
      a = source.getA();
      b = source.getB();
      c = source.getC();
    
      Target target = new Target( a, b, c );
    
      return target;
    }
    

The second approach could be

Target target(Source source) {
    if ( source == null ) {
        return null;
    }

    String a = null;
    String b = null;
    String c = null;

    Target target = new Target( a, b, c );

    target.setA(source.getA());
    target.setA(source.getB());
    target.setA(source.getC());

    return target;
}

Here is how the target object class looks like.

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

@Getters
@Setters
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Target {

@NonNull
private String a;

@NonNull
private String b;

@NonNull
private String c;

}


Solution 1:[1]

The decision which constructor MapStruct will use is defined in the Using Constructors section of the documentation. The rules are the following:

  • If a constructor is annotated with an annotation named @Default (from any package) it will be used.

  • If a single public constructor exists then it will be used to construct the object, and the other non public constructors will be ignored.

  • If a parameterless constructor exists then it will be used to construct the object, and the other constructors will be ignored.

  • If there are multiple eligible constructors then there will be a compilation error due to ambiguous constructors. In order to break the ambiguity an annotation named @Default (from any package) can be used.

From the example you have provided there is a single public constructor (the one from @AllArgsConstructor), this means that MapStruct will use the first approach.

Target target(Source source) {
  if ( source == null ) {
      return null;
  }

  String a = null;
  String b = null;
  String c = null;

  a = source.getA();
  b = source.getB();
  c = source.getC();

  Target target = new Target( a, b, c );

  return target;
}

The second approach from the question is something that doesn't make sense and MapStruct can never generate such a code. If you are seeing something like that then this is a bug.

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 Filip