admin管理员组

文章数量:1288978

I have mappers CatMapper, DogMapper etc. which I want to use in other mappers like ZooMapper, FarmMapper etc. Every time I have to repeat uses = {CatMapper.class, DogMapper.class}.

How to avoid it and "use" them together?

Attempts

Extract to constant

Extract array to constant:

public static final Class<?>[] ANIMAL_MAPPERS = {CatMapper.class, DogMapper.class};

but it's impossible to use it in an annotation attribute because "Attribute value must be constant":

@Mapper(uses = ANIMAL_MAPPERS)

Even if array constant was possible, you can't handle the case with other mappers because runtime in the attribute is not allowed e.g.:

@Mapper(uses = ArrayUtils.addAll(ANIMAL_MAPPERS, new Class[]{OtherMapper.class, YetAnotherMapper.class}))

Grouping mappers and multi-level "uses"

Create mapper that groups all repeatable mappers in uses:

@Mapper(uses = {CatMapper.class, DogMapper.class})
public interface AllAnimalMappers {
}

and use it in every place in uses instead of repetition:

@Mapper(uses = {AllAnimalMappers.class})
public interface ZooMapper {

But it doesn't work. MapStruct doesn't use methods from nested mappers:

ZooMapper.java:[10,12] Unmapped target property: "catWhisper". Mapping from property "Cat cat" to "CatDto cat".
ZooMapper.java:[10,12] Unmapped target property: "dogCall". Mapping from property "Dog dog" to "DogDto dog".

Config (many configs)

Create config that groups all repeatable mappers in uses:

@MapperConfig(uses = {CatMapper.class, DogMapper.class})
public interface AllAnimalMappers {
}

and use it in config (empty uses):

@Mapper(config = AllAnimalMappers.class)
public interface ZooMapper {

It seems to work. But config isn't a list/array, so you can't use many configs in one mapper, for example:

@Mapper(config = {AllAnimalMappers.class, AllBuildingMappers.class})
public interface ZooMapper {

Therefore it's very limited, you can't use it in most cases.

Generic mapper

The problem is more visible in the use cases when you have many mappers because of inheritance and impossibility to create one generic mapper for all child classes (source 1, source 2). You would like to use all extensions together.

All extension in uses in base mapper:

@MapperConfig(uses = {CatMapper.class, DogMapper.class})
public interface AnimalMapper<T, U> {

and use it in mappers:

@Mapper(uses = {AnimalMapper.class})
public interface ZooMapper {

but it also doesn't work (same error as above).

Full example

Domain classes:

public abstract class Animal {
}

@Data
public class Cat {
    private String name;
}

@Data
public class Dog extends Animal {
    private String name;
}

// and more extends Animal

@Data
public class Zoo {
    private String name;
    private Cat cat;
    private Dog dog;
}

@Data
public class Farm {
    private String name;
    private Cat cat;
    private Dog dog;
}

and DTO equivalents:

@Data
public abstract class AnimalDto {
}

@Data
public class CatDto extends AnimalDto {
    private String catWhisper;
}

@Data
public class DogDto extends AnimalDto {
    private String dogCall;
}

// and more extends AnimalDto 

@Data
public class ZooDto {
    private String title;
    private CatDto cat;
    private DogDto dog;
}

@Data
public class FarmDto {
    private String companyName;
    private CatDto cat;
    private DogDto dog;
}

and mappers for them:

@MapperConfig
public interface AnimalMapper<T, U> {
    U toDto(T source);
}

@Mapper
public interface CatMapper extends AnimalMapper<Cat, CatDto> {
    @Mapping(target = "catWhisper", source = "name")
    CatDto toDto(Cat source);
}

@Mapper
public interface DogMapper extends AnimalMapper<Dog, DogDto> {
    @Mapping(target = "dogCall", source = "name")
    DogDto toDto(Dog source);
}

@Mapper(uses = {CatMapper.class, DogMapper.class})
public interface ZooMapper {
    @Mapping(target = "title", source = "name")
    ZooDto toDto(Zoo source);
}

@Mapper(uses = {CatMapper.class, DogMapper.class})
public interface FarmMapper {
    @Mapping(target = "companyName", source = "name")
    FarmDto toDto(Farm source);
}

本文标签: javaMapStructnested multilevel quotusesquot or mappers groupingStack Overflow