mrniko / netty-socketio

Socket.IO server implemented on Java. Realtime java framework
Apache License 2.0
6.82k stars 1.65k forks source link

Float32Array from Javascript // JacksonJsonSupport.DeserializationFeature #201

Open mschrupp opened 9 years ago

mschrupp commented 9 years ago

Hi guys,

nice work you did here. Thank you so much!!

Anyway, I stumbled upon a problem and really need some help. I'm currently trying to pass a Float32Array from Javascript to Java.

The following error occurs:

[nioEventLoopGroup-3-7] ERROR
com.corundumstudio.socketio.JsonSupportWrapper - Can't read value:
["msg","AAAAAAAAQEAAAOBAAABwQQ=="] for type: 
class com.corundumstudio.socketio.protocol.Event

com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of float[] out of VALUE_STRING token

I searched for the code where the exception happens, and you can find the following there:

if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)) {
    throw ctxt.mappingException(_valueClass);
}
return new float[] { _parseFloatPrimitive(jp, ctxt) };

I think I have to enable this DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY. The Float32Array seems to be interpreted as a "single value" by the deserializer. You can get the JacksonJsonSupport from com.corundumstudio.socketio.Configuration, but there is no chance to change the Features there, they are hardcoded in the init():

protected void init(ObjectMapper objectMapper) {
    (...)
    objectMapper.setSerializationInclusion(Include.NON_NULL);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN, true);
    objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}

... and also private.

Any idea or help on this? Do I need to fork? Is the problem somewhere else, maybe in my JavaScript? The strange thing is, with Uint8Array (JavaScript) to byte[] (Java) it works without a problem.

So here is the code I use in Javascript:

socket.on("connect", function(){
    console.log("connect");

    socket.on("msg", function(p){
        console.log(new Float32Array(p));
        console.log(p);

    });

    socket.binaryType = 'arraybuffer';
    var myData = new Float32Array([0.0, 1.1, 2.2, 3.3]).buffer;
    socket.emit('msg', myData);
});

Finally: Does netty-socketio support binary within complex objects? It does not work with custom object in addEventListener, set function fails with Conflicting setter definitions for property

This is the syntax as supported by socket.io:

// it's possible to embed binary data
// within arbitrarily-complex objects
socket.emit('image', { image: true, buffer: buf });

as stated in http://socket.io/blog/introducing-socket-io-1-0/#binary

mrniko commented 9 years ago

You may do it like this:

    config.setJsonSupport(new JacksonJsonSupport(config) {
        @Override
        protected void init(ObjectMapper objectMapper) {
            super.init(objectMapper);
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        }
    });
mrniko commented 9 years ago

Does netty-socketio support binary within complex objects?

Yes. Check BinaryEventLauncher in netty-socketio-demo project

tselishev-semen commented 9 years ago

@jesusofsuburbia try this, maybe it will help you


 function arrayBufferToBase64 (buffer) {
            var binary = '';
            var bytes = new Uint8Array(buffer);
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
                binary += String.fromCharCode(bytes[i]);
            }
            return window.btoa(binary);
        }
 var myData = new Float32Array([0.0, 1.1, 2.2, 3.3]).buffer;
    socket.emit('msg', arrayBufferToBase64(myData));

although, this is unlikely to help you :)

mschrupp commented 9 years ago

@tselishev-semen thought about that already, but thanks alot anyway :+1:

@mrniko I know about the netty-socketio-demo project, but where can I see embedded binary in javascript objects there?

like

{
    data : new Float32Array().buffer,
    id : "somestring"
}

And thanks for the JacksonJsonSupport example provided above, currently trying to do this! :+1: