Mapstruct with abstract and wildcard

5.6k views Asked by At

I have the following code :

public class EntityA {
  private List<? extends AbstractObject> objects;
}

public class EntityB {
  private List<? extends AbstractObjectDTO> dtos;
}

I have a generic mapper :

public interface GenericMapper<X extends AbstractObjectDTO, Y extends AbstractObject> {

  Y mapDTOToEntity(X value);

  X mapEntityToDTO(Y value);
}

@Mapper
public interface ConcreteMapper extends GenericMapper<ConcreteDTO, ConcreteObject> {}

At compile time it generates the following error : Can't map property "List<? extends AbstractObject> objects" to "List<? extends AbstractObjectDTO> dtos". Consider to declare/implement a mapping method: "List<? extends AbstractObjectDTO> map(List<? extends AbstractObject> value)".

And when I do implement the map method as shown in the error I have the following error : Can't generate mapping method for a generic type variable source.

How to map the lists properly ?

2

There are 2 answers

0
Filip On BEST ANSWER

You can achieve what you are looking for.

You need to have the following methods:

List<AbstractObjectDto> map(List<? extends AbstractObject> value);

List<AbstractObject> mapDto(List<? extends AbstractObjectDto> value);

@ObjectFactory
default AbstractObjectDto createDto() {
    return null; // implement your own logic
}

@ObjectFactory
default AbstractObject createEntity() {
    return null; // implement your own logic
}

The most important thing would be how should MapStruct generate the objects that you are mapping. MapStruct generates code during compile them so you would need to implement that appropriately.

If you want to find out the types during runtime then you would even need to do something like:

default AbstrctObjectDto map(AbstractObject value) {

    if (value instanceOf SomeObject) {
        // invoke mapping for SomeObject
    }
    //else if and more 
}
0
Yogi On

In MapStruct generalization works using MapperConfig.

You need to define MapperConfig like

@MapperConfig(mappingInheritanceStrategy=MappingInheritanceStrategy.AUTO_INHERIT_FROM_CONFIG)
public interface MapConfig{

  AbstractObject mapToObject(AbstractObjectDTO dto);
  AbstractObjectDTO mapToDTO(AbstractObject ob);

}

And use this config in your mapper class like:

@Mapper(config=MapConfig.class)
public interface YourMapperinterfacce{

 //Concrete object mappings

}

I have not tried generic stuff, you can try with MapperConfig.