如何在子类映射中使用qualifiedByName。

huangapple go评论83阅读模式
英文:

How to use qualifiedByName with subclass mapping

问题

You can achieve this by specifying the qualifiedByName attribute in the @BeanMapping annotation for the toMatchApiMissing method in your DetailsApiMapper. Here's how you can modify the DetailsApiMapper:

@Mapper(uses = {
        LolDetailsApiMapper.class,
        CsgoDetailsApiMapper.class,
        DotaDetailsApiMapper.class
})
public interface DetailsApiMapper {

    @BeanMapping(unmappedTargetPolicy = IGNORE, qualifiedByName = "toMatchApiMissing")
    @SubclassMapping(target = Match.class, source = LolMatchDetails.class)
    @SubclassMapping(target = Match.class, source = CsgoMatchDetails.class)
    @SubclassMapping(target = Match.class, source = DotaMatchDetails.class)
    Match toApi(MatchDetails matchDetails);

    @BeanMapping(unmappedTargetPolicy = IGNORE, qualifiedByName = "toMatchApiMissing")
    @SubclassMapping(target = Match.class, source = LolMatchDetails.class)
    @SubclassMapping(target = Match.class, source = CsgoMatchDetails.class)
    @SubclassMapping(target = Match.class, source = DotaMatchDetails.class)
    Match toMatchApiMissing(MatchDetails matchDetails);

}

By specifying qualifiedByName = "toMatchApiMissing" in both @BeanMapping annotations for the toMatchApiMissing method, you're telling MapStruct to use the toMatchApiMissing method in the specific mappers (e.g., LolDetailsApiMapper, CsgoDetailsApiMapper, or DotaDetailsApiMapper) that have this method with the same qualified name. This should make DetailsApiMapper.toMatchApiMissing use the toMatchApiMissing of the other mappers correctly.

英文:

I have the following mappers:

@Mapper(uses = ApiMapper.class,
        // Disable use of the builders which we mostly need for testing.
        builder = @Builder(disableBuilder = true))
public interface CsgoDetailsApiMapper {

    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toApi(CsgoMatchDetails matchDetails);

    @Named("toMatchApiMissing")
    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails", qualifiedByName = "toGameApiMissing")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toMatchApiMissing(CsgoMatchDetails matchDetails);

    ...
}

Similar to this I have two more mappers looking exactly the same. LolDetailsApiMapper and DotaDetailsApiMapper

then I have a details mapper that should use the implementation of the specific mappers:

@Mapper(uses = {
        LolDetailsApiMapper.class,
        CsgoDetailsApiMapper.class,
        DotaDetailsApiMapper.class
})
public interface DetailsApiMapper {

    @BeanMapping(unmappedTargetPolicy = IGNORE)
    @SubclassMapping(target = Match.class, source = LolMatchDetails.class)
    @SubclassMapping(target = Match.class, source = CsgoMatchDetails.class)
    @SubclassMapping(target = Match.class, source = DotaMatchDetails.class)
    Match toApi(MatchDetails matchDetails);

    @BeanMapping(unmappedTargetPolicy = IGNORE)
    @SubclassMapping(target = Match.class, source = LolMatchDetails.class)
    @SubclassMapping(target = Match.class, source = CsgoMatchDetails.class)
    @SubclassMapping(target = Match.class, source = DotaMatchDetails.class)
    Match toMatchApiMissing(MatchDetails matchDetails);

}

How can I make the DetailsApiMapper.toMatchApiMissing use the toMatchApiMissing of the other mappers, instead of the toApi? I tried adding @Named("toMatchApiMissing") to the specific mappers and then tried to use @BeanMapping(unmappedTargetPolicy = IGNORE, qualifiedByName="toMatchApiMissing"), but this didn't work. Is this possible? Thanks in advance.

答案1

得分: 0

尝试在所有子类映射器的toApi方法上使用@Named进行注解,而不是使用toMatchApiMissing方法,如下所示:

@Mapper(uses = ApiMapper.class,
        // Disable use of the builders which we mostly need for testing.
        builder = @Builder(disableBuilder = true))
public interface CsgoDetailsApiMapper {

    @Named("toApi")
    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toApi(CsgoMatchDetails matchDetails);

    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails", qualifiedByName = "toGameApiMissing")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toMatchApiMissing(CsgoMatchDetails matchDetails);
}

然后重新构建项目并检查生成的映射器实现。这是一个奇怪的解决方案,但在我的情况下,Mapstruct选择了正确的映射方法,即那些没有使用@Named进行注解的方法。

编辑:

我找到了与该主题相关的问题,似乎即将发布的1.6.0里程碑版本将允许在SubclassMapping注解中使用限定符。

发布后,您将能够定义子类映射如下:

@SubclassMapping(target = Match.class, source = CsgoMatchDetails.class, qualifiedByName = "toMatchApiMissing")
英文:

Try to annotate toApi method in all subclass mappers with @Named, instead of toMatchApiMissing method, as shown below:

@Mapper(uses = ApiMapper.class,
        // Disable use of the builders which we mostly need for testing.
        builder = @Builder(disableBuilder = true))
public interface CsgoDetailsApiMapper {

    @Named("toApi")
    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toApi(CsgoMatchDetails matchDetails);

    @Mapping(target = "title", source = "match.title")
    @Mapping(target = "status", source = "match.state")
    @Mapping(target = "teams", source = "match.teams")
    @Mapping(target = "games", source = "gameDetails", qualifiedByName = "toGameApiMissing")
    @Mapping(target = "id", source = "match.id")
    @Mapping(target = "facts", source = "matchDetails")
    Match toMatchApiMissing(CsgoMatchDetails matchDetails);
}

Then rebuild the project and check the generated mapper implementation. It's a weird solution, but in my case, Mapstruct picked the right methods for mapping, i.e. those not annotated with @Named.

EDIT:

I've found the issue related to the topic, and it appears that the upcoming 1.6.0 milestone release will enable the use of qualifiers within the SubclassMapping annotation.

After the release, you will be able to define a subclass mapping as follows:

@SubclassMapping(target = Match.class, source = CsgoMatchDetails.class, qualifiedByName = "toMatchApiMissing")

huangapple
  • 本文由 发表于 2023年6月6日 02:23:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76409073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定