gpt4 book ai didi

java - 将 Java int[][] 的神秘 bytea 表示形式转换回数组(Hibernate)

转载 作者:行者123 更新时间:2023-12-01 13:35:38 24 4
gpt4 key购买 nike

长话短说,我需要使用 Java 6(或 SQL)将 bytea 从 PostgreSQL 转换为 int[][]。

如果您需要上下文,请随意阅读下面的内容,但这实际上就是全部内容。

上下文

曾经在我所在团队工作的人写了一个这样的 bean:

public class FourPointBean {
@Column(name = "points", length = "65535")
private int[][] xy;
... other irrelevant stuff
}

其中 int[][] 实际上只有四个点(不知道他为什么选择 int[][]...)

(xy[0][0], xy[0][1]) := (x0, y0)
(xy[1][0], xy[1][1]) := (x1, y1)
(xy[2][0], xy[2][1]) := (x2, y2)
(xy[3][0], xy[3][1]) := (x3, y3)

显然,多年来 Hibernate 一直抛出一个每个人都忽略的异常,因为它“只是一个警告”——

WARNING: duplicate class definition bug occured? Please report this :
com/company/blah/SomeBean$JaxbAccessorM_getXy_setXy_Array_Of_[I
java.lang.ClassFormatError: Illegal class name
"com/company/blah/SomeBean$JaxbAccessorM_getXy_setXy_Array_Of_[I" in class file
com/company/blah/SomeBean$JaxbAccessorM_getXy_setXy_Array_Of_[I
at java.lang.ClassLoader.defineClass1(Native Method)
...

结果是 Hibernate 将 int 数组作为 byta 插入表中。最终这个 bean 定义实际上引起了一些问题,所以我改变了它 --

public class FourPointBean {
@Type(type = "com.company.blah.PointArrayType")
@Column(name = "points", length = 65535, columnDefinition = "int[][]")
private int[][] xy;
... other irrelevant stuff
}

然后我将 UI 使用的 DTO 更改为:

public class FourPointDTO {

private List<Point> points = Lists.newArrayListWithCapacity(4);
...
}

这一切都很好,但现在我必须编写一些东西来使用 Java 6 将相关表中所有困惑的现有字节数组迁移到 PostgreSQL int[]... .

我在网上看到的所有内容都涉及一维数组,这些数组没有完全转换...现在我什至不知道如何将 int[][] 转换为字节数组以进行测试。

一如既往,非常感谢您的帮助...

<小时/>

编辑

这里有一些翻译--

<小时/>

(00525bc5f039-2d70-40f0-922c-0ef7060816be)

int[][]

[0][0] := 538
[0][1] := 760
[1][0] := 676
[1][1] := 760
[2][0] := 676
[2][1] := 890
[3][0] := 538
[3][1] := 890

字节

 \xaced0005757200035b5b4917f7e44f198f893c020000787000000004757200025b494dba602676eab2a50200007870000000020000021a000002f87571007e000200000002000002a4000002f87571007e000200000002000002a40000037a7571007e0002000000020000021a0000037a
<小时/>

(005276c1cb74-2476-43bf-856e-43912e969000)

int[][]

[0][0] := 544
[0][1] := 638
[1][0] := 657
[1][1] := 638
[2][0] := 657
[2][1] := 743
[3][0] := 544
[3][1] := 743

字节

 \xaced0005757200035b5b4917f7e44f198f893c020000787000000004757200025b494dba602676eab2a5020000787000000002000002200000027e7571007e000200000002000002910000027e7571007e00020000000200000291000002e77571007e00020000000200000220000002e7

最佳答案

简短版本:看起来 Hibernate 正在保存 int[][] 类型的序列化 Java 对象。总的。使用封装在 ObjectInputStream 中的 ByteArrayInputStream 在 Java 中对其进行反序列化。

<小时/>

要获取原始字节,请使用如下 Python 代码片段:

points_hex = open("/path/to/points.txt").readlines()
points = [ p[2:-1].strip().decode("hex") for p in points_hex ]

有效。我怀疑有一个共同的前缀,所以我检查了。由 this nice easy longest-common-prefix algo 提供:

from itertools import takewhile,izip

def allsame(x):
return len(set(x)) == 1

r = [i[0] for i in takewhile(allsame ,izip(*points))]
''.join(r).encode("hex")

已确认:

\xaced0005757200035b5b4917f7e44f198f893c020000787000000004757200025b494dba602676eab2a50200007870000000020000

像这样的前缀的存在强烈表明我们正在处理一个序列化的Java对象,而不是数组中一系列点的字节表示。将点的原始二进制文件写入文件后,可以使用 file 轻松确认这一点:

open("/tmp/point","w").write(points[0])

然后在外壳中:

$ file /tmp/point 
/tmp/point: Java serialization data, version 5

您应该使用 Java 将这些点反序列化为 int[][] 来解码这些点。对于 SQL 中的 int[][] 这样的简单对象是可能的,但是当您只能要求 Java 为您处理它时,手动执行它是没有意义的。

更新:

我感觉很好,所以这里是解码它的 Java 代码:

import java.io.*;
import java.util.Arrays;

public class Deserialize {

// Credit: https://stackoverflow.com/a/140861/398670
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}


public static void main( String[] args ) throws Exception {
if (args.length != 1) {
System.err.println("Usage: java Deserialize aced....hexstring...");
System.exit(1);
}

String hex = args[0];
if (hex.startsWith("\\x")) {
hex = hex.substring(2);
}

ByteArrayInputStream bis = new ByteArrayInputStream(hexStringToByteArray(hex));
ObjectInput in = new ObjectInputStream(bis);
Object obj_read = in.readObject();

if (obj_read instanceof int[][]) {
int[][] obj_arr = (int[][]) obj_read;
System.err.println("Array contents are: " + Arrays.deepToString(obj_arr) );
}
}

}

用法:

$ javac Deserialize.java 
$ java Deserialize '\xaced0005757200035b5b4917f7e44f198f893c020000787000000004757200025b494dba602676eab2a50200007870000000020000021a000002f87571007e000200000002000002a4000002f87571007e000200000002000002a40000037a7571007e0002000000020000021a0000037a'
Array contents are: [[538, 760], [676, 760], [676, 890], [538, 890]]

当然,实际上您将使用 PgJDBC,它直接为您提供一个 byte[],因此您不必执行我上面所做的十六进制解码。

关于java - 将 Java int[][] 的神秘 bytea 表示形式转换回数组(Hibernate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21296570/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com