Binary event #6

Closed
flowersinthesand opened this Issue Mar 3, 2016 · 2 comments

Comments

Projects
None yet
1 participant
@flowersinthesand
Member

flowersinthesand commented Mar 3, 2016

Derived from cettia/cettia-protocol#9

With this feature, you will be able to exchange events whose data is binary without binary-to-text conversion.

  • Find MessagePack Java implementation
  • Implement the default behavior of send method

@flowersinthesand flowersinthesand added this to the 1.0.0-Alpha3 milestone Mar 3, 2016

@flowersinthesand

This comment has been minimized.

Show comment
Hide comment
@flowersinthesand

flowersinthesand Mar 5, 2016

Member

As for MessagePack Java Implementation, msgpack-java looks the best. It also provides Jackson extension, msgpack-jackson.

Map<String, Object> obj = new LinkedHashMap<>();
obj.put("text", "Donghwan Kim");
obj.put("binary", "Donghwan Kim".getBytes());

ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
byte[] bytes = objectMapper.writeValueAsBytes(obj);
System.out.println(Arrays.toString(bytes));
System.out.println(objectMapper.readValue(bytes, Map.class));
[-126, -92, 116, 101, 120, 116, -84, 68, 111, 110, 103, 104, 119, 97, 110, 32, 75, 105, 109, -90, 98, 105, 110, 97, 114, 121, -60, 12, 68, 111, 110, 103, 104, 119, 97, 110, 32, 75, 105, 109]
{text=Donghwan Kim, binary=[B@38fc30b8}
Member

flowersinthesand commented Mar 5, 2016

As for MessagePack Java Implementation, msgpack-java looks the best. It also provides Jackson extension, msgpack-jackson.

Map<String, Object> obj = new LinkedHashMap<>();
obj.put("text", "Donghwan Kim");
obj.put("binary", "Donghwan Kim".getBytes());

ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
byte[] bytes = objectMapper.writeValueAsBytes(obj);
System.out.println(Arrays.toString(bytes));
System.out.println(objectMapper.readValue(bytes, Map.class));
[-126, -92, 116, 101, 120, 116, -84, 68, 111, 110, 103, 104, 119, 97, 110, 32, 75, 105, 109, -90, 98, 105, 110, 97, 114, 121, -60, 12, 68, 111, 110, 103, 104, 119, 97, 110, 32, 75, 105, 109]
{text=Donghwan Kim, binary=[B@38fc30b8}
@flowersinthesand

This comment has been minimized.

Show comment
Hide comment
@flowersinthesand

flowersinthesand Mar 5, 2016

Member

The second task is about how a given object should be serialized into either text message (JSON) or binary message (MessagePack).

First ObjectMapper's convertValue doesn't touch byte arrays and ByteBuffer instances.

public static class TestBean {
  // Getters and setters are skipped
  public String string = "100";
  public int number = 100;
  public Map<String, Object> object = new LinkedHashMap();
  public byte[] byteArray = new byte[]{-126, -92, 116, 101, 120, 116, -84, 68, 111, 110, 103, 104,
    119, 97, 110, 32, 75, 105, 109, -90, 98, 105, 110, 97, 114, 121, -60, 12, 68, 111, 110,
    103, 104, 119, 97, 110, 32, 75, 105, 109};
  public ByteBuffer byteBuffer = ByteBuffer.wrap("small".getBytes());

  {
    {
      object.put("integer", 300);
      object.put("bytes", ByteBuffer.wrap("big".getBytes()));
    }
  }
}

ObjectMapper mapper = new ObjectMapper();
Map map = mapper.convertValue(new TestBean(), Map.class);
System.out.println(map);
{string=100, number=100, object={integer=300, bytes=[B@2a37783b}, byteArray=[B@1fb67f24, byteBuffer=[B@65524c0}

Second to determine if a given object contains binary (if so, it should be encoded to binary), it's required to traverse the given object. Using SimpleModule's addSerializer, ByteArraySerializer and ByteBufferSerializer, we don't need to visit every property of the given object manually considering stuff like circular structure.

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
// Of course thread safety is not required here
final AtomicBoolean containsBinary = new AtomicBoolean();
module.addSerializer(byte[].class, new ByteArraySerializer() {
  @Override
  public void serialize(byte[] bytes, JsonGenerator gen, SerializerProvider provider) throws
    IOException {
    containsBinary.set(true);
    super.serialize(bytes, gen, provider);
  }
});
module.addSerializer(ByteBuffer.class, new ByteBufferSerializer() {
  @Override
  public void serialize(ByteBuffer bytes, JsonGenerator gen, SerializerProvider provider)
    throws IOException {
    containsBinary.set(true);
    super.serialize(bytes, gen, provider);
  }
});
mapper.registerModule(module);

Map map = mapper.convertValue(new TestBean(), Map.class);
System.out.println(map);
System.out.println(containsBinary);
{string=100, number=100, object={integer=300, bytes=[B@65524c0}, byteArray=[B@3fdfbc7f, byteBuffer=[B@79d0569b}
true

If it turns out that it has binary, new ObjectMapper(new MessagePackFactory()) and writeValueAsBytes should be used to encode it to MessagePack and if not new ObjectMapper() and writeValueAsString should be used to encode it to JSON.

Member

flowersinthesand commented Mar 5, 2016

The second task is about how a given object should be serialized into either text message (JSON) or binary message (MessagePack).

First ObjectMapper's convertValue doesn't touch byte arrays and ByteBuffer instances.

public static class TestBean {
  // Getters and setters are skipped
  public String string = "100";
  public int number = 100;
  public Map<String, Object> object = new LinkedHashMap();
  public byte[] byteArray = new byte[]{-126, -92, 116, 101, 120, 116, -84, 68, 111, 110, 103, 104,
    119, 97, 110, 32, 75, 105, 109, -90, 98, 105, 110, 97, 114, 121, -60, 12, 68, 111, 110,
    103, 104, 119, 97, 110, 32, 75, 105, 109};
  public ByteBuffer byteBuffer = ByteBuffer.wrap("small".getBytes());

  {
    {
      object.put("integer", 300);
      object.put("bytes", ByteBuffer.wrap("big".getBytes()));
    }
  }
}

ObjectMapper mapper = new ObjectMapper();
Map map = mapper.convertValue(new TestBean(), Map.class);
System.out.println(map);
{string=100, number=100, object={integer=300, bytes=[B@2a37783b}, byteArray=[B@1fb67f24, byteBuffer=[B@65524c0}

Second to determine if a given object contains binary (if so, it should be encoded to binary), it's required to traverse the given object. Using SimpleModule's addSerializer, ByteArraySerializer and ByteBufferSerializer, we don't need to visit every property of the given object manually considering stuff like circular structure.

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
// Of course thread safety is not required here
final AtomicBoolean containsBinary = new AtomicBoolean();
module.addSerializer(byte[].class, new ByteArraySerializer() {
  @Override
  public void serialize(byte[] bytes, JsonGenerator gen, SerializerProvider provider) throws
    IOException {
    containsBinary.set(true);
    super.serialize(bytes, gen, provider);
  }
});
module.addSerializer(ByteBuffer.class, new ByteBufferSerializer() {
  @Override
  public void serialize(ByteBuffer bytes, JsonGenerator gen, SerializerProvider provider)
    throws IOException {
    containsBinary.set(true);
    super.serialize(bytes, gen, provider);
  }
});
mapper.registerModule(module);

Map map = mapper.convertValue(new TestBean(), Map.class);
System.out.println(map);
System.out.println(containsBinary);
{string=100, number=100, object={integer=300, bytes=[B@65524c0}, byteArray=[B@3fdfbc7f, byteBuffer=[B@79d0569b}
true

If it turns out that it has binary, new ObjectMapper(new MessagePackFactory()) and writeValueAsBytes should be used to encode it to MessagePack and if not new ObjectMapper() and writeValueAsString should be used to encode it to JSON.

@flowersinthesand flowersinthesand referenced this issue in cettia/cettia-javascript-client Mar 6, 2016

Closed

Binary event #9

2 of 2 tasks complete

flowersinthesand added a commit that referenced this issue Apr 10, 2016

Regards ext format whose type is in 0x11-0x1D not 0x1B and 0x1C as bi…
…n format

msgpack-lite that is one of dependencies of cettia-javascript-client encodes typed arrays to ext format. But in Java they should be decoded as bin format.

Refs #6

@flowersinthesand flowersinthesand self-assigned this Feb 11, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment