Расширение существующего интерфейса Mapstruct для добавления дополнительных методов сопоставления - PullRequest
0 голосов
/ 09 июля 2020

У меня есть картограф Mapstruct, который уже определен в общей библиотеке, которая в настоящее время используется моим приложением. У меня есть новый метод сопоставления, который я хочу добавить к этому сопоставителю, и он c указан в моем приложении, поэтому я не хочу изменять исходный сопоставитель, чтобы добавить эту функциональность.

Я попытался расширить интерфейс, но я продолжаю сталкиваться с проблемами. В настоящее время с приведенным ниже кодом он будет компилироваться, но выдает исключения времени выполнения, поскольку Mapstruct не создает класс MyMapperExtendedImpl.

Вызвано: java .lang.RuntimeException: java .lang. ClassNotFoundException: не удалось найти реализацию для com.whatever.package.name.MyMapperExtended

У меня есть предупреждение от Sonar о том, что когда я пытаюсь получить доступ к картографу, вызывая Mappers.getMapper (MyMapperExtended. class) , что у него нет аннотации @Mapper. Затем я изменил MyMapperExtended.class, удалив аннотацию @MapperConfig и заменив ее тем же @ Mapper (imports = {SomeUtilityClass.class}) из родительского сопоставителя. Код больше не компилируется, и у меня есть ряд ошибок, в которых говорится, что не удается найти определенные переменные. Эти переменные выглядят как параметры функции, поскольку их имена точно совпадают.

Как правильно расширить существующий интерфейс MyMapper, чтобы добавить к нему дополнительные методы сопоставления?

@MapperConfig(uses = MyMapper.class)
public interface MyMapperExtended extends MyMapper {

    default List<ChildClass> someObjectListToChildClassList(List<SomeObject> someList) {
        //Some special logic here and looping which makes it so cannot use the @Mapping annotations
        
        //Call the mapper for the parent so that the base properties are mapped 
        ParentClass mappedParentClass = this.someObjectListToParentClassList(someList);
        
        //Uses a copy constructor to copy over the mapped base properties
        ChildClass myChildClass = new ChildClass(mappedParentClass);
        myChildClass.setExtraProperty("whatever value");

        return myChildClass;
    }
}

Mapper из общая общая библиотека

@Mapper(imports = { SomeUtilityClass.class })
public interface MyMapper {
    @Mapping(target = "id", source = "someId")
    @Mapping(target = "name", source = "name")
    @Mapping(target = "someFieldWeIgnoreWhileMapping", ignore = true)
    ParentClass someObjectListToParentClass(SomeObject someObject)

    List<ParentClass> someObjectListToParentClassList(List<SomeObject> someList)
}

Классы ParentClass и ChildClass также отображаются (упрощено, поэтому не отображаются геттеры / сеттеры для переменных-членов)

public class ParentClass {
    UUID id; 
    String name;
    String someFieldWeIgnoreWhileMapping;

    public ParentClass() {}
}

public class ChildClass {
    String extraProperty; 

    public ChildClass(ParentClass parent) {
        super();
        this.setId(parent.getId());
        this.setName(parent.getName());
    }
}

Класс SomeObject, который используется в качестве исходного объекта для отображения

public class SomeObject {
    UUID someId; 
    String name; 
    String someFieldWeIgnore; 

    public SomeObject () {}
}

1 Ответ

0 голосов
/ 10 июля 2020

После проработки нескольких разных вопросов. Я наконец-то заставил его "работать" там, где он будет генерировать код, но он не будет работать для моего варианта использования. Я исключил использование «выражения» из кода, который я разместил выше, потому что в то время я не думал, что это актуально, но это вызывает последнюю проблему.

@Mapping(target = "id", source = "someId")
@Mapping(target = "name", source = "name")
@Mapping(target = "someFieldWeIgnoreWhileMapping", ignore = true)
@Mapping(expression = "java(SomeUtilityClass.doSomethingHelpful(someObject.getSpecialField()))", target = "specialField")
ParentClass someObjectListToParentClass(SomeObject someObject);

Сгенерированный код из Mapstruct выглядит примерно так это.

public ParentClass someObjectListToParentClass(SomeObject arg0) {
    if (arg0 == null) {
        return null;
    } else { 
        ParentClass parentClass = new ParentClass();
        parentClass.setId(arg0.getId()); 
        parentClass.setName(arg0.getName());

        //The problem. 
        //It puts the variable name as "someObject" because that's what the expression is hardcoded as in the Interface, but the varible is actually arg0 here 
        parentClass.setSpecialField(SomeUtilityClass.doSomethingHelpful(someObject.getSpecialField()));
    }
}

Для всех, у кого нет такого сценария, как мой, похоже, что просто добавление @Mapper должно работать (включая ВСЕ импортированные файлы, если они есть). Я решил просто создать отдельный маппер вместо того, чтобы наследовать от оригинального.

...