简体   繁体   English

在jackson生成的json中包装协议缓冲区时java中的错误?

[英]Error in java while wrapping protocol buffer inside json generated by jackson?

I'm sending and receiving HTTP post requests by doing the following: 我通过执行以下操作发送和接收HTTP post请求:

FooJson fooJson = new FooJson();
fooJson.setName("Bob");

FooProto.Builder fooProto = FooProto.newBuilder(); // google protobuf
fooProto.setColor("Blue");
fooProto.setLength(30);

BarProto.Builder barProto = BarProto.newBuilder();
barProto.setWeight(65);
fooProto.setBarProto(barProto);

barJson.setFooProto(new String(fooProto.build().toByteArray()));
List<BarJson> barJsonList = new ArrayList<BarJson>();
barJsonList.add(barJson);
fooJson.setBarJsonList(barJsonList);
String data = writeJson(fooJson); // wrapper for jackson JsonGenerator
RequestEntity re = new ByteArrayRequestEntity(data.getBytes());

PostMethod method = new PostMethod("http://foo.net:123/path");
method.setRequestEntity(re);
httpClient.executeMethod(method);

On the receiving end, I parse with the following: 在接收端,我解析以下内容:

FooJson fooJson = readJson(request.getInputStream(), FooJson.class);
for (BarJson barJson : fooJson.getBarJsonList()) {
    FooProto fooProto = FooProto.parseFrom(barJson.getFooProto().getBytes());
}

The result during parsing of the protocol buffer on the receiving end is: 解析接收端协议缓冲区时的结果是:

com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field.  This could mean either than the input has been truncated or that an embedded message misreported its own length.

Am I doing something wrong with the way I'm converting the protocol buffer to a string? 我是否正在将协议缓冲区转换为字符串的方式出错? How might I be able to fix this? 我怎么能解决这个问题?

I doubt that you can reliably tunnel protobuf (whose payload is pure binary, not text) through JSON without doing some type of encoding like base64 or hex encoding. 我怀疑你可以通过JSON可靠地隧道protobuf(其有效载荷是纯二进制,而不是文本),而无需进行某种类型的编码,如base64或十六进制编码。 Convert your protobuf payload from bytes into base64 text. 将protobuf有效负载从字节转换为base64文本。 Then on the receiving end convert it from base64 text back to binary. 然后在接收端将它从base64文本转换回二进制文件。

You are getting the protobuf exception because the byte array on the receiving end does not match the protobuf payload you sent. 您正在获取protobuf异常,因为接收端的字节数组与您发送的protobuf有效负载不匹配。 The data got munged when you converted to a string and back without using some type of encoding. 当您转换为字符串并返回而不使用某种类型的编码时,数据会被释放。

I have had good luck with javax.xml.bind.DatatypeConverter. 我对javax.xml.bind.DatatypeConverter运气不错。 It's part of Java 1.6. 它是Java 1.6的一部分。 Use printBase64Binary on the sending side and parseBase64Binary on the receiving side. 在发送端使用printBase64Binary,在接收端使用parseBase64Binary。

[update] [更新]

Alternatively, if base64 is just too ugly, you can serialize your protobuf objects into several different string formats (JSON, XML) with protobuf-java-format . 或者,如果base64太丑陋,您可以使用protobuf-java-format将protobuf对象序列化为几种不同的字符串格式(JSON,XML)。 This might look a little weird because the barJson.setFooProto would contain a string which is itself a JSON payload. 这可能看起来有点奇怪,因为barJson.setFooProto将包含一个本身就是JSON有效负载的字符串。 There would be a lot of escaped quote characters - but it should work. 将会有很多转义引号字符 - 但它应该有效。

Your mistake is here: 你的错误在这里:

barJson.setFooProto(new String(fooProto.build().toByteArray()));

Do NOT try to create a String from arbitrary binary data -- this will quite likely corrupt the data, depending on encodings in use; 不要尝试从任意二进制数据创建一个字符串 - 这很可能会破坏数据,具体取决于使用的编码; and specifically with JSON, UTF-8 encoding will pretty much guarantee corruption (some byte sequence are not allowed in UTF-8, so you either get an exception or data gets mutated). 特别是使用JSON,UTF-8编码几乎可以保证损坏(UTF-8中不允许某些字节序列,因此您要么获得异常,要么数据发生变异)。

Instead, define field as byte[] , and let Jackson use Base64 encoding. 相反,将字段定义为byte[] ,让Jackson使用Base64编码。 This will be correct, and is done relatively efficiently. 这是正确的,并且相对有效地完成。

You might also want to consider just using JSON for the whole thing, as the first answer suggested. 您可能还想考虑仅使用JSON作为整个事情,如第一个答案所示。 No need to use specific Protobuf flavor either; 无需使用特定的Protobuf风味; you can always construct PB objects separately if you really need them. 如果你真的需要它们,你总是可以单独构造PB对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM