What is the correct way to serialize and deserialize a Map<String, byte[]>
using Jackson?
I had been doing this:
I create a Map<String, byte[]>
:
Map<String, String> contextContents = new HashMap<>();
contextContents.put("a-context-key", "a-context-value");
Map<String, byte[]> context = new HashMap<>();
context.put("outer-key", OBJECT_MAPPER.writeValueAsBytes(contextContents));
I need to put this into a Postgres bytea
column, so I'm doing this:
byte[] toPostgres = OBJECT_MAPPER.writeValueAsBytes(context);
Then reading it out of postgres:
Map<String, byte[]> fromPostgres = OBJECT_MAPPER.readValue(toPostgres, Map.class)
However, when I pass the fromPostgres
field along to another component that tries to serialize it again later:
class MyMessage
{
public Map<String, byte[]> context;
}
MyMessage myMessage = new MyMessage();
myMessage.context = fromPostgres;
I get the following error:
Section of interest:
com.fasterxml.jackson.databind.JsonMappingException: class java.lang.String cannot be cast to class [B (java.lang.String and [B are in module java.base of loader 'bootstrap') (through reference chain: com.amce.MyMessage["context"]->java.util.LinkedHashMap["outer-key"])
Full error:
"exception":"java.lang.ClassCastException: class java.lang.String cannot be cast to class [B (java.lang.String and [B are in module java.base of loader 'bootstrap')
at com.fasterxml.jackson.databind.ser.std.ByteArraySerializer.serialize(ByteArraySerializer.java:30)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFieldsUsing(MapSerializer.java:817)
... 23 common frames omitted
Wrapped by: com.fasterxml.jackson.databind.JsonMappingException: class java.lang.String cannot be cast to class [B (java.lang.String and [B are in module java.base of loader 'bootstrap') (through reference chain: com.amce.MyMessage[\"context\"]->java.util.LinkedHashMap[\"outer-key\"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:397)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:356)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFieldsUsing(MapSerializer.java:822)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:641)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:722)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4110)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3437)
at
I found an answer on this post:
https://stackoverflow.com/a/48639642/12177456
Instead of:
Map<String, byte[]> fromPostgres = OBJECT_MAPPER.readValue(toPostgres, Map.class)
use:
TypeReference<Map<String, byte[]>> typeRef
= new TypeReference<Map<String, byte[]>>()
{
};
Map<String, byte[]> fromPostgres = OBJECT_MAPPER.readValue(toPostgres, typeRef);
I'd just like to be sure that this is the correct way to serialize and deserialize a Map<String, byte[]>
, where the byte[]
array could be anything, such as another class etc?