Use case
The code generated by MapStruct is not null-aware and this creates problems when using the annotation processer nullaway. Nullaway assumes all code to be non-null by default and all nullable values to be annotated with @Nullable. Unfortunately MapStruct does not generate compatible code which means we have to turn off nullaway for the generated code which defeats the purpose a bit.
Problem
This does not compile:
public record RenterDto(String id, String name) {
}
public record Renter(RenterId id, String name) {
}
public interface RenterTranslator {
@Mapping(source = "id", target = "id.rawValue")
@Nullable Renter dtoToRenter(@Nullable RenterDto dto);
@Mapping(source = "id.rawValue", target = "id")
@Nullable RenterDto RenterToDto(@Nullable Renter renter);
}
because it generated this code:
@Override
public Renter dtoToRenter(RenterDto dto) {
if ( dto == null ) {
return null; // <-- returns null which is not ok because the return value is not marked as @Nullable
}
RenterId id = null; // <!-- not the correct default value, null is not allowed, but nullaway is smart enough the figure out that id will be set to a correct value below
String name = null;
id = renterDtoToRenterId( dto );
name = dto.name();
Renter renter = new Renter( id, name );
return renter;
}
If we now add things that are actually nullable, like who rented an item, things become more complex:
public record ItemDto(String id, String name, @Nullable String rentedById) {
}
public record Item(ItemId id, String name, @Nullable RenterId rentedBy) {
}
Now the MapStruct code needs to know that it should only unwrap rentedBy if it is non-null and only wrap rentedById when it is non-null. Otherwise null-away will throw an error again.
Complete example
The complete example can be found here: https://github.com/Richargh/mapstruct-nullaway-mvn-java-limitation
Wish
I'd like MapStruct to interpret @nullable annotations as such. That would also increase the null-safety when using MapStruct with Kotlin.
Generated Code
@Override
public Renter dtoToRenter(RenterDto dto) {
RenterId id = renterDtoToRenterId( dto );
String name = dto.name();
Renter renter = new Renter( id, name );
return renter;
}
protected RenterId renterDtoToRenterId(RenterDto renterDto) {
String rawValue = renterDto.id();
RenterId renterId = new RenterId( rawValue );
return renterId;
}
and
@Override
public Item dtoToItem(ItemDto dto) {
ItemId id = itemDtoToItemId( dto );
String name = dto.name();
RenterId rentedBy = dto.rentedById() == null ? null : new RenterId(dto.rentedById());
Item item = new Item( id, name, rentedBy );
return item;
}
Possible workarounds
Let nullaway ignore @generated code, which unfortunately defeats the purpose of null-safety.
MapStruct Version
1.5.3.Final
Use case
The code generated by MapStruct is not null-aware and this creates problems when using the annotation processer nullaway. Nullaway assumes all code to be non-null by default and all nullable values to be annotated with
@Nullable. Unfortunately MapStruct does not generate compatible code which means we have to turn off nullaway for the generated code which defeats the purpose a bit.Problem
This does not compile:
because it generated this code:
If we now add things that are actually nullable, like who rented an item, things become more complex:
Now the MapStruct code needs to know that it should only unwrap rentedBy if it is non-null and only wrap rentedById when it is non-null. Otherwise null-away will throw an error again.
Complete example
The complete example can be found here: https://github.com/Richargh/mapstruct-nullaway-mvn-java-limitation
Wish
I'd like MapStruct to interpret @nullable annotations as such. That would also increase the null-safety when using MapStruct with Kotlin.
Generated Code
and
Possible workarounds
Let nullaway ignore @generated code, which unfortunately defeats the purpose of null-safety.
MapStruct Version
1.5.3.Final