在Java中使用proto3时,对象中的长值未正确序列化和反序列化
我正在尝试使用proto3在java中序列化和反序列化一个对象。这是我在proto中的对象的样子在Java中使用proto3时,对象中的长值未正确序列化和反序列化,java,protocol-buffers,proto,proto3,Java,Protocol Buffers,Proto,Proto3,我正在尝试使用proto3在java中序列化和反序列化一个对象。这是我在proto中的对象的样子 option java_multiple_files = true; option java_package = "com.project.dataModel"; option java_outer_classname = "FlowProto"; // The request message containing the user's name. message Flow { stri
option java_multiple_files = true;
option java_package = "com.project.dataModel";
option java_outer_classname = "FlowProto";
// The request message containing the user's name.
message Flow {
string subscriberIMSEI = 1;
string destinationIP = 2;
uint64 txBytes = 3;
uint64 rxBytes = 4;
uint64 txPkts = 5;
uint64 rxPkts = 6;
uint64 startTimeInMillis = 7;
uint64 endTimeInMillis = 8;
string asnNumber = 9;
string asnName = 10;
string asnCountryCode = 11;
}
public class Test {
public static void main(String[] args) throws Exception {
Flow flow =
Flow.newBuilder().setAsnName("abc")
.setEndTimeInMillis(123456789L)
.setStartTimeInMillis(123456789L)
.setDestinationIP("1.1.1.1")
.setTxBytes(1L)
.setRxBytes(1L)
.setTxPkts(1L)
.setRxPkts(1L)
.setAsnName("blah")
.setAsnCountryCode("blah")
.build();
byte[] flowByteArray = flow.toByteArray();
String flowString = flow.toByteString().toStringUtf8();
System.out.println("Parsed from ByteArray:" + Flow.parseFrom(flowByteArray).getEndTimeInMillis());
System.out.println("Parsed from ByteString:" + Flow.parseFrom(ByteString.copyFromUtf8(flowString))
.getEndTimeInMillis());
}
}
下面是我在java中的序列化和反序列化的样子
option java_multiple_files = true;
option java_package = "com.project.dataModel";
option java_outer_classname = "FlowProto";
// The request message containing the user's name.
message Flow {
string subscriberIMSEI = 1;
string destinationIP = 2;
uint64 txBytes = 3;
uint64 rxBytes = 4;
uint64 txPkts = 5;
uint64 rxPkts = 6;
uint64 startTimeInMillis = 7;
uint64 endTimeInMillis = 8;
string asnNumber = 9;
string asnName = 10;
string asnCountryCode = 11;
}
public class Test {
public static void main(String[] args) throws Exception {
Flow flow =
Flow.newBuilder().setAsnName("abc")
.setEndTimeInMillis(123456789L)
.setStartTimeInMillis(123456789L)
.setDestinationIP("1.1.1.1")
.setTxBytes(1L)
.setRxBytes(1L)
.setTxPkts(1L)
.setRxPkts(1L)
.setAsnName("blah")
.setAsnCountryCode("blah")
.build();
byte[] flowByteArray = flow.toByteArray();
String flowString = flow.toByteString().toStringUtf8();
System.out.println("Parsed from ByteArray:" + Flow.parseFrom(flowByteArray).getEndTimeInMillis());
System.out.println("Parsed from ByteString:" + Flow.parseFrom(ByteString.copyFromUtf8(flowString))
.getEndTimeInMillis());
}
}
我的输出如下
Parsed from ByteArray:123456789
Parsed from ByteString:-4791902657223630865
当我尝试使用ByteString和utf-8路由进行序列化和反序列化时,哪里出了问题
谢谢 出现问题的原因是序列化字节数组已损坏。这是因为UTF-8是可变长度编码,转换为UTF-8字符串会更改原始数组中的字节。执行
flow.toByteString().toStringUtf8()
时,原始bytestring中的一个字节可能会转换为三个具有不同值的新字节。然后,当您执行ByteString.copyFromUtf8(flowString)
时,字节更改不会撤消,因为该行代码实际上只是检索转换后的UTF-8字节,而不是您输入的原始字节
下面是一个小测试,它说明了您看到的问题
@Test
public void byteConsistency() {
byte[] vals = new byte[] {0, 110, -1};
ByteString original = ByteString.copyFrom(vals);
ByteString newString = ByteString.copyFromUtf8(original.toStringUtf8());
for (int index = 0; index < newString.size(); index++) {
System.out.println(newString.byteAt(index));
}
}
但它实际上是输出的
0
110
-17
-65
-67
这是因为UTF-8可能规定-1(0xFF)字节应编码为三个字节[-17、-65、-67]
总之,在处理protobuf时,不要将序列化对象转换为UTF-8字符串。仅将原始字节用于序列化和反序列化。如果尝试转换为UTF-8字符串,序列化的字节将损坏,您将无法对其进行反序列化。出现问题的原因是序列化的字节数组已损坏。这是因为UTF-8是可变长度编码,转换为UTF-8字符串会更改原始数组中的字节。执行
flow.toByteString().toStringUtf8()
时,原始bytestring中的一个字节可能会转换为三个具有不同值的新字节。然后,当您执行ByteString.copyFromUtf8(flowString)
时,字节更改不会撤消,因为该行代码实际上只是检索转换后的UTF-8字节,而不是您输入的原始字节
下面是一个小测试,它说明了您看到的问题
@Test
public void byteConsistency() {
byte[] vals = new byte[] {0, 110, -1};
ByteString original = ByteString.copyFrom(vals);
ByteString newString = ByteString.copyFromUtf8(original.toStringUtf8());
for (int index = 0; index < newString.size(); index++) {
System.out.println(newString.byteAt(index));
}
}
但它实际上是输出的
0
110
-17
-65
-67
这是因为UTF-8可能规定-1(0xFF)字节应编码为三个字节[-17、-65、-67]
总之,在处理protobuf时,不要将序列化对象转换为UTF-8字符串。仅将原始字节用于序列化和反序列化。如果您尝试转换为UTF-8字符串,序列化的字节将损坏,您将无法对其进行反序列化。是的,我们使用的是Pentaho,它不支持传递字节[]。我最终使用Base64编码将字节[]转换为字符串。是的,我们使用的是Pentaho,它不支持传递字节[]。我最终使用Base64编码将字节[]转换为字符串。