0

I am using MapStruct to convert a database entity to Immutable model object. So Immutable object doesn't have setters but Mapstruct requires setters when mapping objects. So I created an explicit builder using Immutable object builder to provides to Mapstruct. Below are the snippets from code:

@Value.Immutable
@Value.Style(overshadowImplementation = true)
public interface CarModel {
    @Nullable String getCarId();
}
@Mapper(uses = ImmutablesBuilderFactory.class)
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    @Mapping(source = "id", target = "carId")
    ImmutableCarModel.Builder toModel(CarEntity carEntity);
}
public class ImmutablesBuilderFactory {
    public ImmutableCarModel.Builder createCarModelBuilder() {
        return ImmutableCarModel.builder();
    }
}

Below code was generated by Mapstruct:

public class CarMapperImpl implements CarMapper {
    @Autowired
    private final ImmutablesBuilderFactory immutablesBuilderFactory
    @Override
    public Builder toModel(CarEntity carEntity) {
        if ( carEntity == null ) {
            return null;
        }
        Builder builder = immutablesBuilderFactory.createCarModelBuilder();
        if ( carEntity.getId() != null ) {
            builder.carId( carEntity.getId() );
        }
        return builder;
    }
}

I was able to convert an entity to Immutable model object but unit test is failing for this. It is throwing NPE at below line of code in CarMapperImpl class while calling CarMapper.INSTANCE.toModel(carEntity).build(); in unit test

Builder builder = immutablesBuilderFactory.createCarModelBuilder();

Does anyone have any idea what's going wrong here?

slayer
  • 393
  • 1
  • 5
  • 19
  • Calling any method on something that can return null is risky. The code for `toModel` clearly can return `null`, and yet you call `.build()` on it directly without checking for `null` – pafau k. Jun 04 '20 at 22:37
  • Yup I understand that. But NPE is being thrown because immutablesBuilderFactory is null. – slayer Jun 05 '20 at 17:56
  • 1
    It is not possible for `immutablesBuilderFactory` to be `null`. The field is final and a new instance is created in the class. Are you sure that the `CarMapperImpl` looks like in the question? – Filip Jun 05 '20 at 21:45
  • Yup you're correct. ImmutablesBuilderFactory was being Autowired. Modified the question. – slayer Jun 05 '20 at 23:30

2 Answers2

1

The reason for the NPE is because you are mixing the usage of the default and spring component model.

The Mappers#getMapper is only meant to be used with the default component model. When using a dependency injection framework you need to use the framework to get access to the mapper.

Filip
  • 19,269
  • 7
  • 51
  • 60
0

This was due to below property in MapStruct configuration

-Amapstruct.defaultComponentModel=spring

After removing this, Mapstruct was not autowiring and was able to create an instance of ImmutablesBuilderFactory.

slayer
  • 393
  • 1
  • 5
  • 19
  • The problem is not that, but rather the incorrect usage of the library. Have a look at my answer – Filip Jun 07 '20 at 08:59