cubesoft
cubesoft

Reputation: 3550

java jackson json processor - using in RestTemplate on Android and automatic type conversion

I have to write a proxy client in Java to connect to JSON WebService. I have only textual description of WebService methods and types. For instance the result of one method is

Params { byte[] challenge; byte[] proff; }

If I create a class Params in Java with both fields as byte[], jackson mapper treats them as binary arrays and encodes as following example

{"id":2,"method":"Authenticate","params":["bSwY+kKRO7sIJNZFG/L3dK2ke1kIDwzyK5n717MyBG1pnRhjqSF0kRMAyEqLYKA6VBwujaR8K/wr98+G1Av9vQ12soFi+3DViPN4YDguqF0=","2iNJ5UEK3eVxFTEUHMN04QM8WtNrwGSIu1hKVXFMVvQ="]}

The WebService exptects those parameters in a form of comma separated non negative byte values like

[truncated] {"id":2,"method":"Authenticate","params":[[114,109,104,101,70,88,16,32,102,17,117,3,105,104,112,4,39,103,11,54,90,106,90,69,26,20,5,10,121,52,108,64,106,102,52,124,87,8,21,29,28,119,110,70,122,33,105, ...............

I concluded that Jackson mapper uses some kind of automatic Java type recognition and chooses the corresponding JSON type. Is there a way to control it and ie change the type the serializer should use for particular Java type serialization? Where is description and mapping between Java and JSON types?

Regards

Upvotes: 0

Views: 731

Answers (1)

Programmer Bruce
Programmer Bruce

Reputation: 67003

Jackson is representing the byte[] as a base 64 encoded string.

You'll need to implement a custom serializer, to manually iterate through the byte[] and generate the JSON array of integer values.


That didn't work out quite as I expected it should.

import java.io.IOException;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.module.SimpleModule;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(new Bar()));
    // output: {"bytes":"AQIDBAUGBwgJCgsMDQ4PEA=="}

    SimpleModule module = new SimpleModule("byte[] as integers", Version.unknownVersion());
    module.addSerializer(byte[].class, new ByteArrayAsIntegersSerializer());
    mapper = new ObjectMapper().withModule(module);
    System.out.println(mapper.writeValueAsString(new Bar()));
    // output: {"bytes":"AQIDBAUGBwgJCgsMDQ4PEA=="}
    // ByteArrayAsIntegersSerializer was not used!

    module = new SimpleModule("byte[] as integers 2", Version.unknownVersion());
    module.addSerializer(Bar.class, new BarSerializer());
    mapper = new ObjectMapper().withModule(module);
    System.out.println(mapper.writeValueAsString(new Bar()));
    // output: {"bytes":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}
  }
}

class Bar
{
  public byte[] bytes = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
}

class BarSerializer extends JsonSerializer<Bar>
{
  @Override
  public void serialize(Bar value, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException
  {
    jgen.writeStartObject();
    jgen.writeFieldName("bytes");
    jgen.writeStartArray();
    for (byte b : value.bytes)
      jgen.writeNumber(b);
    jgen.writeEndArray();
    jgen.writeEndObject();
  }
}

class ByteArrayAsIntegersSerializer extends JsonSerializer<byte[]>
{
  @Override
  public void serialize(byte[] bytes, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException
  {
    jgen.writeStartArray();
    for (byte b : bytes)
      jgen.writeNumber(b);
    jgen.writeEndArray();
  }
}

Upvotes: 1

Related Questions