当前位置: 首页 > 知识库问答 >
问题:

组织。推土机。MappingProcessor-字段映射错误ByteArray

东郭源
2023-03-14

我有以下实体、DTO类和推土机映射文件。我正在尝试使用推土机映射将包含2个微弱字节数组的Hibernate实体复制到新的DTO。获取java.lang.IllegalArgumentException:数组元素类型不匹配。

有什么想法吗?

映射文件:

<mapping map-id="i" wildcard="false">
        <class-a>com.csinfra.jdbmon.web.client.dto.Config.HostGroups.HostGroup.CheckGroup.Check.Type.MultiResult</class-a>
        <class-b>com.csinfra.jdbmon.web.client.dto.MultiResultDTO</class-b>
        <field>
            <a>id</a>
            <b>id</b>
        </field>
        <field>
            <a>columns</a>
            <b>columns</b>
        </field>                        
    </mapping>

实体类:

    @Entity(name="multiResult")
@Table(name="multiResult")
public static class MultiResult implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @javax.persistence.Column(name = "id", unique = true, nullable = false)
    private Long id;

    @Lob
    @javax.persistence.Column(name = "columns",length = 10000)
    private byte[][] columns;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public byte[][] getColumns() {
        return columns;
    }

    public void setColumns(byte[][] columns) {
        this.columns = columns;
    }
}    

DTO等级:

public class MultiResultDTO implements IsSerializable {

    private Long id;
    private byte[][] columns;

    public MultiResultDTO(){}

    public byte[][] getColumns() {
        return columns;
    }

    public void setColumns(byte[][] columns) {
        this.columns = columns;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }   
}

例外情况:

19165 ERROR org.dozer.MappingProcessor - Field mapping error -->
  MapId: null
  Type: null
  Source parent class: com.csinfra.jdbmon.web.client.dto.Config$HostGroups$HostGroup$CheckGroup$Check$Type$MultiResult
  Source field name: columns
  Source field type: class [[B
  Source field value: [[B@127a7396
  Dest parent class: com.csinfra.jdbmon.web.client.dto.MultiResultDTO
  Dest field name: columns
  Dest field type: [[B
java.lang.IllegalArgumentException: array element type mismatch
    at java.lang.reflect.Array.set(Native Method)
    at org.dozer.MappingProcessor.addToPrimitiveArray(MappingProcessor.java:712)
    at org.dozer.MappingProcessor.mapArrayToArray(MappingProcessor.java:629)
    . . .
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

共有1个答案

霍襦宗
2023-03-14

这要么是一个设计决策,要么是一个bug。我在一个更简单的环境中复制了它并归档。似乎可以对代码进行修补,以至少支持多维数组(多维集合仍然不能以这种方式工作),但我这样做只是为了证明构建一个全新对象的“快乐路径”的概念,省略了目标对象可能已经具有非空字段的部分。在所有情况下,需要做大量的工作来支持这一点,这表明仅支持一维集合和数组是一个设计决策。但这只是我的想法,我第一次看到了这些代码,也许我们会从有经验的推土机开发人员那里获得更多信息。

话虽如此,您可以通过为“columns”参数(或者实际上为任何1-d或2-d字节数组)编写自定义转换器,轻松克服特定情况下的这种情况。

一种更长但更干净的方法IMO(不依赖于推土机参与其中,因为这似乎有点不可靠):定义转换器类

public class ByteArray2dConverter extends DozerConverter<byte[][], byte[][]> {

    public ByteArray2dConverter() {
        super(byte[][].class, byte[][].class);
    }

    public byte[][] convertTo(byte[][] source, byte[][] destination) {
        if (source == null) {
            return null;
        }
        byte[][] result = new byte[source.length][];
        for (int i = 0; i < source.length; i++) {
            byte[] element = source[i];
            if (element != null) {
                result[i] = Arrays.copyOf(element, element.length);
            }
        }
        return result;
    }

    public byte[][] convertFrom(byte[][] source, byte[][] destination) {
        return convertTo(source, destination);
    }
}

...并将自定义转换器属性添加到XML映射文件中的“列”字段:

<mapping map-id="i" wildcard="false">
    <class-a>com.csinfra.jdbmon.web.client.dto.Config.HostGroups.HostGroup.CheckGroup.Check.Type.MultiResult</class-a>
    <class-b>com.csinfra.jdbmon.web.client.dto.MultiResultDTO</class-b>
    ...
    <field custom-converter="com.csinfra...ByteArray2dConverter">
        <a>columns</a>
        <b>columns</b>
    </field>
</mapping>

或者,如果允许推土机映射“顶级”数组,并且仅对第二级使用自定义转换器:定义转换器,则可以保存一些键入

public class ByteArray1dConverter extends DozerConverter<byte[], byte[]> {

    public ByteArray1dConverter() {
        super(byte[].class, byte[].class);
    }

    public byte[] convertTo(byte[] source, byte[] destination) {
        return source == null ? null : Arrays.copyOf(source, source.length);
    }

    public byte[] convertFrom(byte[] source, byte[] destination) {
        return convertTo(source, destination);
    }
}

...然后在映射XML中添加一个部分(与“映射”部分在同一级别):

...
<configuration>
    <custom-converters>
        <converter
                type="com.csinfra...ByteArray1dConverter">
            <class-a>[B</class-a>
            <class-b>[B</class-b>
        </converter>
    </custom-converters>
</configuration>
<mapping map-id="i" wildcard="false">
    ...

这样,您可以告诉Dozer在两个字节数组之间的所有转换中使用您的转换器(您可以在前面的情况下执行相同的操作,而不是在映射XML中的字段级别定义自定义转换器)。

另一种选择是使用对象的一维数组,每个对象都有一个一维字节数组,Dozer对此很在行。类似于Column[]columns,其中Column类有一个字段。

 类似资料:
  • 我试图使用Dozer映射UUID字段,遇到了Dozer github上提到的一个问题: https://github.com/DozerMapper/dozer/issues/83 问题是-显然,Dozer依赖于UUID中不存在的默认无参数构造函数。因此,该链接显示了如何告知推土机执行参考复制。然而,使用该提示并没有帮助,我仍然会遇到以下异常: org.dozer.java.lang.java.u

  • 我有一个非常复杂的对象。 我的目标是将问题答案集映射展平,以便将值中的所有列表合并为一个 我没有试图找出如何在Dozer中将所有这些列表合并到一个列表中,我甚至不确定它是否能够做到,而是编写了一个自定义setter。 我假设这意味着Dozer只需读取第一个对象的调查并将其放入makeFlatSurvey,但它读取调查对象上的questionAnswerGroup字段,然后遍历QuestionAns

  • 我在Spring启动时使用推土机映射器。如果我将数据从实体映射到EntityDTO,那么dozer maper的工作就是将数据从实体类复制到EntityDTO,对于原语也是如此。但是假设我有这样一门课 和名称为EntityDTO的DTO 那么它不会将数据从entityChild映射到EntityChildTos,有人能帮我解决这个问题吗?

  • 我是使用dozer的新手。我需要将集合映射到一个类,该类是集合中源类的属性。我有如下类技术 我想映射到 哪里 我的推土机绘图将是什么样子?

  • 在Dozer的帮助下,我想将映射到DTO类 但是这两种设置

  • 我在srcopobject中收集了StateTax和LocalTax。这需要映射到StateLocalTax的集合。在SrcObject中,如果我有三个SrcStateTax和两个SrcLocalTax,我想将它们映射到一个StateLocalTax集合,该集合将有四个元素。此集合的三个元素将包含stateTax信息和null destLocalTaxGroup,一个元素将包含destLocalT