Here we have a class that has been serialized polymorphically, so the
json looks like:
"@class" : "com.basistech.dm.ListAttribute",
"itemClass" : "com.basistech.dm.EntityMention",
"items" : [ {
"startOffset" : 16,
"endOffset" : 39,
"entityType" : "ORGANIZATION",
"source" :
"gazetteer:/Users/benson/x/trunk/rlp/rlp/dicts/en-all-gazetteer-LE.bin",
"normalized" : "Samsung Electronics"
},
On entry to a custom deserializer, the next token is not the object
start, nor neither the field after the @class field. Line 9 has the
@class, but there's no column 50.
Using Jackson 2.3.0. I'm guessing I'm entered pointing at the value of @class.
com.fasterxml.jackson.databind.JsonMappingException: Unexpected token
(VALUE_STRING), expected FIELD_NAME: Expected itemClass
at [Source: [B@6335605a; line: 9, column: 50]
public class ListAttributeDeserializer extends JsonDeserializer<ListAttribute> {
@Override
@SuppressWarnings("unchecked")
public ListAttribute deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException {
if (!jp.nextFieldName(new SerializedString("itemClass"))) {
throw ctxt.wrongTokenException(jp, JsonToken.FIELD_NAME,
"Expected itemClass");
}
String itemClassName = jp.nextTextValue();
Class<? extends BaseAttribute> itemClass = null;
try {
itemClass = (Class<? extends BaseAttribute>)
ctxt.findClass(itemClassName);
} catch (ClassNotFoundException e) {
throw new JsonMappingException("Failed to find class " +
itemClassName);
}
if (!jp.nextFieldName(new SerializedString("items"))) {
throw ctxt.wrongTokenException(jp, JsonToken.FIELD_NAME,
"Expected items");
}
List<BaseAttribute> items = Lists.newArrayList();
if (jp.nextToken() != JsonToken.START_ARRAY) { // what about nothing?
throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY,
"Expected array of items");
}
while (jp.nextToken() != JsonToken.END_ARRAY) {
items.add(jp.readValueAs(itemClass));
}
ListAttribute.Builder<BaseAttribute> builder = new
ListAttribute.Builder<BaseAttribute>((Class<BaseAttribute>)
itemClass);
builder.setItems(items);
return builder.build();
}
}
Tatu, did you mean to write that the problem is that JsonDeserializer
does not override or that my class does not? I appreciate that the fix
is for me to add this in, but I am just curious as to where the fix
belongs in the first place. I'll take your advice about the
nextFieldName.
This sure was a 'fight with generic' party, to boot.
Your proposed change did not change the behavior at all.
Tatu, did you mean to write that the problem is that JsonDeserializer
does not override or that my class does not? I appreciate that the fix
is for me to add this in, but I am just curious as to where the fix
Your proposed change did not change the behavior at all.
--
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/groups/opt_out.
Tatu,Tatu, the code as written works: the first nextToken() skips the "itemClass": field name, so that the subsequent getText() gets the value. I'm bugging you because it surprised me.The 'if' you suggest would make it work even if the type didn't happen to be used in a context with @class.
Or did the test fail for you?
Anyway, if you remind me of which repo contains JsonDeserializer, I'll give you a patch with javadoc containing what you just wrote :-)