ModelMapper:基于子类选择映射 [英] ModelMapper: Choose mapping based on Child class

查看:137
本文介绍了ModelMapper:基于子类选择映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR

我想使用modelMapper,将其从AbstractParent映射到AbstractParentDTO,然后在ModelMapper-Config中为每个子类调用特定的映射器,然后跳过其余的(抽象类)映射.

I want to use modelMapper in a way that I map from AbstractParent to AbstractParentDTO and later in the ModelMapper-Config call the specific mappers for each Sub-class and then skip the rest of the (abstrac-class) mappings.

那怎么可能?这是正确的方法吗?有设计缺陷吗?

How is that Possible? Is this the right approach? Is there a design flaw?

我所拥有的:

父实体:

@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public abstract class Parent {
//some more fields
}

一个子实体:

//Basic Lombok Annotations
@DiscriminatorValue("child_a")
public class ChildA extends Parent {
//some more fields
}

另一个子实体:

@DiscriminatorValue("child_b")
public class ChildB extends Parent {
//some more fields   
}


然后我有父DTO类:


Then I have the parent DTO class:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@JsonSubTypes.Type(value = ChildA.class, name = "child_a"),
@JsonSubTypes.Type(value = ChildB.class, name = "child_b"),
public abstract class ParentDTO {
//some more fields
}

一个孩子的DTO:

public class ClassADTO extends ParentDTO {
//some more fields
}

和另一个DTO:

public class ClassBDTO extends ParentDTO {
//some more fields
}


就我而言,我将从控制器获取DTO,并在将其提供给服务时将其映射到实体.我必须在5-6个端点中做同样的事情.


In my case I'll get DTO's from the controller and map them to Entities when giving them to the Service. I'll have to do the same thing in 5-6 Endpoints.

端点大致如下:

@PreAuthorize(CAN_WRITE)
@PutMapping("/{id}")
public ResponseEntity<ParentDTO> update(
        @PathVariable("id") UUID id,
        @RequestBody @Valid ParentDTO parentDTO) {

    Parent parent = parentService.update(id, parentDTO);

    if (parentDTO instanceof ChildADTO) {
        return ResponseEntity.ok(modelMapper.map(parent, ChildADTO.class));
    } else if (parentDTO instanceof ChildBDTO) {
        return ResponseEntity.ok(modelMapper.map(parent, ChildBDTO.class));
    }
    throw new BadRequestException("The Parent is not Valid");
}

只有我再有几个孩子使事情变得更笨重.

Only that I have a few more Childs that make things even bulkier.

我想要的东西:

我并不想写很多次DTO(或实体)是什么实例,而只是想写例如:

Instead of checking a bunch of times what instance the DTO (or Entity) is, I simply want to write for example:

modelmapper.map(parent, ParentDTO.class)

并在我的ModelMapper配置中执行实例..."检查一次.

and do the "instance of..." check ONCE in my ModelMapper Configuration.

我尝试过的事情:

对于我在ModelMapper配置中定义的每个可能的方向和映射案例,我已经有不同的Converter(因为它们仍然需要更复杂的映射).

I already have different Converters for every possible direction and mapping-case defined in my ModelMapper Configuration (since they require more complex mapping anyways).

我试图通过为父类再编写一个Converter并将其设置为ModelMapper PreConverter来解决问题:

I've tried to solve my problem by writing one more Converter for the Parent Classes and setting it as a ModelMapper PreConverter:

    //from Entity to DTO
    Converter<Parent, ParentDTO> parentParentDTOConverter = mappingContext -> {
        Parent source = mappingContext.getSource();
        ParentDTO dest = mappingContext.getDestination();

        if (source instanceof CHildA) {
            return modelMapper.map(dest, ChildADTO.class);
        } else if (source instanceof ChildB) {
            return modelMapper.map(dest, ChildBDTO.class);
        } 
        return null;
    };

和:

modelMapper.createTypeMap(Parent.class, ParentDTO.class)
                .setPreConverter(parentParentDTOConverter);

但是我总是遇到相同的MappingError:

But I'm always getting the same MappingError:

1)无法实例化目的地实例 com.myexample.data.dto.ParentDTO.确保这件事 com.myexample.data.dto.ParentDTOO具有非私有无参数 构造函数.

1) Failed to instantiate instance of destination com.myexample.data.dto.ParentDTO. Ensure that com.myexample.data.dto.ParentDTOO has a non-private no-argument constructor.

我得到的

(我猜是),我无法构造抽象类的Object.但这不是我要尝试的,是吗? 我猜想在完成我的PreConverter之后,modelMapper仍在进行其余的映射.我也尝试过使用.setConverter进行设置,但始终具有相同的结果.

which I get (I guess), I cannot construct an Object of an abstract class. But thats not what I'm trying, am I? I guess that modelMapper is still doing the rest of the Mapping after finishing with my PreConverter. I've also tried to set it with .setConverter but always with the same result.

  • 有人知道如何禁用"自定义映射吗?我不 真的很想写像映射器一样的伪映射器" 为每种情况调用特定的映射器.

  • Does anyone knows how to 'disable' the custom mappings? I don't really want to write "pseudo-mappers" that act like mappers and just call the specific mappers for each scenario.

我的设计不好吗?您将如何改进它?

Is my design just bad? How would you improve it?

这还没有在ModelMapper中实现吗?

Is this just not implemented into ModelMapper yet?

任何帮助和提示,我们将不胜感激.

Any help and hint is appreciated.

推荐答案

我将使用ObjectMapper而不是ModelMapper.

I would use ObjectMapper instead of ModelMapper.

父级类中,添加了获得鉴别值的可能性.

In Parent class add the possibility to get the discriminator value.

//..
public class Parent {

    @Column(name = "type", insertable = false, updatable = false)
    private String type;
    //getters and setters
}

您的ParentDTO应该映射到Child(*)DTO

Your ParentDTO should be mapped to Child(*)DTO

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = ChildADTO.class, name = "child_a"),
        @JsonSubTypes.Type(value = ChildBDTO.class, name = "child_b")
})
 public abstract class ParentDTO {
   // ..
 }

在转换服务/方法中,添加一个带有未知未知(忽略您在DTO类中未声明的内容)的对象映射器

in the conversion service/method add an object mapper with ignore unknown (to ignore what you did not declare in your DTO class)

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

只需调用:

Parent parent = // get from repository
ParentDTO parentDTO = objectMapper.readValue(objectMapper.writeValueAsBytes(parent), ParentDTO.class);

这样,您的ParentDTO总是用正确的类型实例化.

In this way, your ParentDTO is always instantiated with the right type.

这篇关于ModelMapper:基于子类选择映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆