我试图使用Gson来获取一些Java Object并将其序列化为json并获取一个表示该Json的字节数组。我需要一个字节数组,因为我将输出传递给外部依赖项,要求它是一个字节数组。
public byte[] serialize(Object object){
return gson.toJson(object).getBytes();
}
我有两个问题:
String
然后转换为byte[]
可能会产生一些不必要的开销。获得byte[]
是否有更优化的方法? 答案 0 :(得分:0)
编辑:我对第1点的回答是错误的。
2)如果你只是使用香草gson转换器,反射会有很多不必要的开销。在您的情况下编写自定义适配器非常有性能优势。这是一篇文章,其中包含更多信息 https://open.blogs.nytimes.com/2016/02/11/improving-startup-time-in-the-nytimes-android-app/?_r=0
答案 1 :(得分:0)
如果输入是String,则gson似乎按原样返回String。它不会对输入进行任何验证。这是预期的吗?
是的,这很好。它只返回给定字符串的JSON字符串表示。
我想以一种方式使用Gson,它会验证输入对象实际上是Json。我怎么能这样做?
无需本身。 Gson.toJson()
方法接受要序列化的对象,并始终生成有效的JSON。如果你的意思是反序列化,那么Gson会在读取/解析/反序列化期间对无效的JSON文档进行快速失败(实际读取时,这是Gson的最底层)。
我将在短时间内调用此序列化函数数千次。转换为String然后转换为byte []可能是一些不必要的开销。是否有更优化的方法来获取byte []?
是的,当然,为了暴露其内部char[]
克隆而累积JSON字符串是一种内存浪费。 Gson基本上是一个面向流的工具,请注意有Gson.toJson
方法重载接受Appendable
基本上是Gson核心(只需快速了解Gson.fromJson(Object)
如何工作 - 它只需创建一个StringWriter
实例来累积字符串,因为Appendable
接口)。如果Gson可以通过Reader
发出JSON令牌而不是写入Appendable
,那将是非常酷的,但是这个idea被拒绝了,很可能永远不会在Gson中实现。由于Gson在反序列化过程中不会以读取语义方式(从代码角度)发出JSON令牌,因此必须缓冲整个结果:
private static byte[] serializeToBytes(final Object object)
throws IOException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final OutputStreamWriter writer = new OutputStreamWriter(outputStream);
gson.toJson(object, writer);
writer.flush();
return outputStream.toByteArray();
}
这个不使用StringWriter
因此不会累积带有克隆数组乒乓的中间字符串。我不知道是否有可以利用/重用现有字节数组的编写器/输出流,但我相信应该有一些,因为它为你在问题中提到的性能目的提供了一个很好的理由。
如果可能,您还可以检查库接口/ API以某种方式公开/接受OutputStream
- 然后您可以轻松地将此类输出流传递给serializeToBytes
方法,甚至可以删除方法。如果它可以使用输入流,而不仅仅是字节数组,您还可以查看converting output streams to input streams,以便serializeToBytes
方法可以返回InputStream
或Reader
(需要一些开销,但可以处理无限数据 - 需要找到余额):
private static InputStream serializeToByteStream(final Object object)
throws IOException {
final PipedInputStream inputStream = new PipedInputStream();
final OutputStream outputStream = new PipedOutputStream(inputStream);
new Thread(() -> {
try {
final OutputStreamWriter writer = new OutputStreamWriter(outputStream);
gson.toJson(object, writer);
writer.flush();
} catch ( final IOException ex ) {
throw new RuntimeException(ex);
} finally {
try {
outputStream.close();
} catch ( final IOException ex ) {
throw new RuntimeException(ex);
}
}
}).start();
return inputStream;
}
使用示例:
final String value = "foo";
System.out.println(Arrays.toString(serializeToBytes(value)));
try ( final InputStream inputStream = serializeToByteStream(value) ) {
int b;
while ( (b = inputStream.read()) != -1 ) {
System.out.print(b);
System.out.print(' ');
}
System.out.println();
}
输出:
[34,102,111,111,34]
34 102 111 111 34
两者都代表一个ASCII代码数组,字面意思是字符串"foo"
。