杰克逊杰森,编组ByteBuffer

jac*_*ver 2 java json jackson

对ByteBuffer中应该存在的数据的最小大小是否有任何限制,以便Jackson能够序列化它?这样做我得到BufferUnderflowException.但是当存在的数据量很大时,它可以正常工作.

public class MyTest {
    private static class Wrapper {
        private ByteBuffer buffer;
        public void setBuffer(ByteBuffer buffer) {
            this.buffer = buffer;
        }
        public ByteBuffer getBuffer() {
            return buffer;
        }
    }

    @Test
    public void fails() throws Exception {
        // Fails
        ByteBuffer smallBuffer = ByteBuffer.wrap("small".getBytes());
        Wrapper wrapper1 = new Wrapper();
        wrapper1.setBuffer(smallBuffer);
        System.out.println(new ObjectMapper().writeValueAsBytes(wrapper1));
    }

    @Test
    public void works() throws Exception {
        // Works
        ByteBuffer smallBuffer = ByteBuffer.wrap("larger string works, wonder why".getBytes());
        Wrapper wrapper1 = new Wrapper();
        wrapper1.setBuffer(smallBuffer);
        System.out.println(new ObjectMapper().writeValueAsBytes(wrapper1));
    }

}
Run Code Online (Sandbox Code Playgroud)

异常堆栈跟踪:

org.codehaus.jackson.map.JsonMappingException: (was java.nio.BufferUnderflowException) (through reference chain: com.test.Wrapper["buffer"]->java.nio.HeapByteBuffer["int"])
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218)
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183)
    at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158)
Run Code Online (Sandbox Code Playgroud)

Per*_*ion 5

当使用大量内部状态和/或非标准getter/setter方法序列化复杂对象时,Jackson通常会遇到问题.通常,您应始终坚持要序列化的对象层次结构中的纯POJO.

在这种特殊情况下,您已经创建了一个包含ByteBuffer的包装器.好吧,杰克逊实际上试图序列化整个字节缓冲区对象(而不仅仅是它的字节内容),如果你看一下它实际上试图写出所有这些'属性':

[
    property 'short' (via method java.nio.HeapByteBuffer#getShort), 
    property 'char' (via method java.nio.HeapByteBuffer#getChar),
    property 'int' (via method java.nio.HeapByteBuffer#getInt),
    property 'long' (via method java.nio.HeapByteBuffer#getLong),
    property 'float' (via method java.nio.HeapByteBuffer#getFloat),
    property 'double' (via method java.nio.HeapByteBuffer#getDouble),
    property 'direct' (via method java.nio.HeapByteBuffer#isDirect),
    property 'readOnly' (via method java.nio.HeapByteBuffer#isReadOnly)
]
Run Code Online (Sandbox Code Playgroud)

它只是运气不好,第二种情况起作用(因为缓冲区足够长,可以在上面调用所有上面显示的方法而不会下溢).如果要将缓冲区序列化为字节,则可以:

  • 将包装器属性更改为 byte[]
  • 将属性保持为ByteBuffer,但将其标记为@JsonIgnore能够并在其周围提供替换的存取方法,以转换为byte[]

第一个例子:

class Wrapper {
    final byte[] buffer;

    public Wrapper(final ByteBuffer buffer) {
        super();
        this.buffer = buffer != null ? buffer.array() : new byte[0];
    }
}
Run Code Online (Sandbox Code Playgroud)