QName serailization without namesampe/prefix

24 views
Skip to first unread message

Anand Nalya

unread,
Aug 26, 2014, 3:58:56 AM8/26/14
to jackso...@googlegroups.com

I'm trying to serialze a Map using Jackson 2, the default ObjectMapper() gives something like:

{"{http://google.com/}myName":"myValue"}

It probably uses QName.toString() method to serialize the qname key.

I tried following to register a custom serializer for QName, but it is not getting invoked.

public static class QnameSerializer extends JsonSerializer<QName> {
    @Override
    public void serialize(QName value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeString(value.getLocalPart());
    }
}

public static void main(String[] args) throws JsonProcessingException {
    SimpleModule module = new SimpleModule();
    module.addKeySerializer(QName.class, new QnameSerializer());
    // tried module.addSerializer(QName.class, new QnameSerializer()) also
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(module);
    Map<QName, String> m =ImmutableMap.of(new QName("http://google.com/","myName","pre"), "myValue");
    System.out.println(mapper.writeValueAsString(m));
}

Am I missing something?

Tatu Saloranta

unread,
Aug 26, 2014, 11:20:44 PM8/26/14
to jackso...@googlegroups.com
That should work for QNames as keys. But I am guessing your problem may rather be due to type erasure, which makes Map instance looks to be of type 'Map<?,?>', and hence key serializer in use would be "Untyped" key serializer.

If this is the root problem, it only affects serializing Maps as root (main-level) values; Map-valued properties should use proper declared (static) type for locating more specific serializer.
You can verify whether this is indeed what causes the issue by creating a wrapper POJO like

   public class MapWrapper {
      public Map<QName,String> map = ...;
   }

and serializing that to see if it works. For now I assume type erasure is to blame here.

There are couple of ways to work around the issue; simplest is often to use a throw-away type like

   public class QNameMap<V> extends HashMap<QName, V>() { }

which will actually retain type information (via super type declaration).

Alternative ObjectWriter has a way to specify static type to use:

    ObjectWriter w = mapper.writerWithType(new TypeReference<Map<QName,String>>() { });
     String json = w.writeValueAsString(m);

which should also work.

Another thing is to perhaps just avoid using non-POJO root values: since type erasure only affects root values, avoiding use of Collections and Maps for root values can prevent quite a few issues.

I hope this helps,

-+ Tatu +-



--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Anand Nalya

unread,
Aug 27, 2014, 2:05:13 AM8/27/14
to jackso...@googlegroups.com
Thanks for the help Tatu. 

I've got this working with mapper.writerWithType. 

While going through jackson code, I found that com.fasterxml.jackson.databind.ser.std.StdKeySerializer is used for writing out keys for map by default. Following is the code for serialize method

@Override
    public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        if (value instanceof Date) {
            provider.defaultSerializeDateKey((Date) value, jgen);
        } else {
            jgen.writeFieldName(value.toString());
        }
    }

I was wondering, if this class can be enhanced for check for registered serializers for value on the basis of value class determined at runtime as it does for Date class.

Regards,
Anand

Tatu Saloranta

unread,
Aug 27, 2014, 2:13:27 AM8/27/14
to jackso...@googlegroups.com
In theory that would be possible, but the problem is cost of lookup on per-key basis, given that this is the commonly used serializer that handles String, Long and Integer keys
There should be efficient lazily constructed data struct to keep track of key serializers to use if this was done. So in the end it's question of how much effort should be put here.

.-+ Tatu +-

Reply all
Reply to author
Forward
0 new messages