org.dozer.MappingProcessor - 字段映射错误 ByteArray
org.dozer.MappingProcessor - Field mapping error ByteArray
我有以下实体、DTO class 和推土机映射文件。我正在尝试使用推土机映射将包含 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>
实体class:
@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 class:
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)
这要么是设计决定,要么是错误。我将其复制 in a simpler setting and filed. It seems that it's possible to patch the code to at least support multidimensional arrays (multidimensional collections still don't work this way), but I only did that 作为构建全新对象 "happy path" 的概念证明,省略了目标对象可能已经具有非空字段的部分。在所有情况下需要完成的工作量都非常大,这暗示仅支持一维集合和数组是一个设计决策。但这只是我的看法,我是第一次看到该代码,也许我们会在某个时候从经验丰富的 Dozer 开发人员那里获得更多信息。
话虽如此,您可以通过为 "columns" 参数(或实际上为任何 1-d 或 2-d 字节数组)编写自定义转换器来轻松克服特定情况下的问题。
一种更长但更简洁的方法 IMO(不依赖 Dozer 参与其中,因为这似乎有点 不可靠):定义一个转换器 class
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 映射文件中的 "columns" 字段:
<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 映射 "top-level" 数组并且仅对第二级使用自定义转换器,则可以节省一些输入:定义一个转换器
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 中添加一个部分(与 "mapping" 部分处于同一级别):
...
<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
,其中列 class 有一个字段 byte[] columnBytes
.
我有以下实体、DTO class 和推土机映射文件。我正在尝试使用推土机映射将包含 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>
实体class:
@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 class:
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)
这要么是设计决定,要么是错误。我将其复制 in a simpler setting and filed. It seems that it's possible to patch the code to at least support multidimensional arrays (multidimensional collections still don't work this way), but I only did that 作为构建全新对象 "happy path" 的概念证明,省略了目标对象可能已经具有非空字段的部分。在所有情况下需要完成的工作量都非常大,这暗示仅支持一维集合和数组是一个设计决策。但这只是我的看法,我是第一次看到该代码,也许我们会在某个时候从经验丰富的 Dozer 开发人员那里获得更多信息。
话虽如此,您可以通过为 "columns" 参数(或实际上为任何 1-d 或 2-d 字节数组)编写自定义转换器来轻松克服特定情况下的问题。
一种更长但更简洁的方法 IMO(不依赖 Dozer 参与其中,因为这似乎有点 不可靠):定义一个转换器 class
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 映射文件中的 "columns" 字段:
<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 映射 "top-level" 数组并且仅对第二级使用自定义转换器,则可以节省一些输入:定义一个转换器
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 中添加一个部分(与 "mapping" 部分处于同一级别):
...
<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
,其中列 class 有一个字段 byte[] columnBytes
.