【问题标题】:org.dozer.MappingProcessor - Field mapping error ByteArrayorg.dozer.MappingProcessor - 字段映射错误 ByteArray
【发布时间】:2018-01-07 12:17:56
【问题描述】:

我有以下实体、DTO 类和推土机映射文件。我正在尝试使用推土机映射将包含 2 个暗字节数组的休眠实体复制到新的 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)

【问题讨论】:

    标签: java hibernate mapping dozer


    【解决方案1】:

    这要么是设计决定,要么是错误。我复制了它in a simpler settingfiled。似乎可以修补代码以至少支持多维数组(多维集合仍然不能这样工作),但我只是 did that 作为构造一个全新对象的“快乐路径”的概念证明,省略目标对象可能已经具有非空字段的部分。在所有情况下都需要做大量的工作来支持这一点,这暗示着只支持一维集合和数组是一个设计决定。但这只是我的看法,我第一次看到该代码,也许我们会在某个时候从经验丰富的 Dozer 开发人员那里获得更多信息。


    话虽如此,在您的特定情况下,您可以通过为“列”参数(或实际上为任何一维或二维字节数组)编写自定义转换器来轻松克服这一问题。

    一种更长但更简洁的方式 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);
        }
    }
    

    ...并将custom-converter 属性添加到您的 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>
    

    或者,如果您允许 Dozer 映射“顶级”数组并且仅对第二级使用自定义转换器,则可以节省一些输入:定义转换器

    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 类有一个字段byte[] columnBytes

    【讨论】:

    • Offtopic:话虽如此,我对像这样的解决方案(推土机)高度怀疑,它给项目带来了魔力和复杂性,同时降低了类型安全性、重构安全性等。而且它更慢而且效率也低于直接的“复制”代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 2011-10-31
    • 2018-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多