Mapstruct Unable To Generate Mapping Methods For Generics

25 Views Asked by At

Given the following classes...

@Data
public class ProductDTD {

  private String id;
  private String name;
}

@Data
public class CustomizationDTD<T extends ProductDTD> {

  private final T product;
  private final String description;
}

@Data
public class Customization {

  private String productId;
  private String description;
}

... I need to convert CustomizationDTD to Customization and vice-versa. Here is my mapper:

@Mapper(componentModel = "spring")
interface CustomizationConverter {

  @Mapping(
      target = "product",
      source = "customization.productId",
      qualifiedByName = "resolve")
  CustomizationDTD<? extends ProductDTD> convert(final Customization customization);

  @Mapping(
      target = "productId",
      source = "product.id")
  Customization convert(final CustomizationDTD<? extends ProductDTD> customizationDTD);

  @Named("resolve")
  default ProductDTD resolve(final String productId) {
    // CapDTD inherits from ProductDTD
    CapDTD cap = capRepository.findById(productId);
    ...
    return cap;
  }
}

The code above does not compile and I always get the following error message:

error: Can't generate mapping method for a wildcard extends bound result.
  CustomizationDTD<? extends ProductDTD> convert(
                                         ^

How do I fix this? Is there any workaround?

1

There are 1 best solutions below

0
Filip On BEST ANSWER

The error that MapStruct gives

error: Can't generate mapping method for a wildcard extends bound result.
  CustomizationDTD<? extends ProductDTD> convert(

is on purpose. When having ? extends ProductDTO, MapStruct has no way of knowing what type it should generate for ?.

One of your options is to return CustomizationDTO<ProductDTO>.

Another option is to have a custom mapping method for this.

@Mapper(componentModel = "spring")
interface CustomizationConverter {

  @Mapping(
      target = "product",
      source = "customization.productId",
      qualifiedByName = "resolve")
  default CustomizationDT)<? extends ProductDTO> convert(final Customization customization) {
        if (customization == null) {
            return null;
        }

        CustomizationDTO<? extends ProductDTO> dto = new CustomizationDTO();

        dto.setDescription(customization.getDescription());
        dto.setProduct(resolve(customization.getProductId());

        return dto;
    }

  @Mapping(
      target = "productId",
      source = "product.id")
  Customization convert(final CustomizationDTD<? extends ProductDTD> customizationDTD);

  @Named("resolve")
  <T extends ProductDTO> default T resolve(final String productId) {
    // CapDTD inherits from ProductDTD
    CapDTD cap = capRepository.findById(productId);
    ...
    return cap;
  }
}