Having Problem de-serializing to POJO when POJO extends another non-Jackson class

2,895 views
Skip to first unread message

James Pinkerton

unread,
Jan 13, 2016, 1:56:14 PM1/13/16
to jackson-user
I am trying to do the following:


 R1Builder.mapper.treeToValue(node, b);

where node is a JsonNode and b is a class B that extends A.

A is an abstract class without a constructor

B has the appropriate constructor with @JsonCreator and @JsonProperty annotations.

I get the error: -E- Caught exception; com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class A],

but I gave it b.

Thanks so much for the help!

James

Tatu Saloranta

unread,
Jan 13, 2016, 1:59:17 PM1/13/16
to jackson-user
It is impossible to give definitely reason without seeing actual class definitions.
But it sounds like you have a Map<> somewhere with key type that is not a simple scalar type.
If so, you would have to provide a custom KeyDeserializer for it, and annotate with

@JsonDeserialize(keyUsing=MyKeyDeserializer.class)

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.

James Pinkerton

unread,
Jan 13, 2016, 5:14:38 PM1/13/16
to jackson-user
This is what I'm tring:



public class Test {

  @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="class")
  @JsonSubTypes({@Type(value = B.class, name = "B")})
  public abstract class A {
  
  }

  public B extends A {
    @JsonCreator
    public B(@JsonProperty("filename") String filenameBase) {


    }

  }


  public static void main(String[] args) {

    ObjectMapper mapper = new ObjectMapper();
    JsonNode root = mapper.readTree(new File(JSONFilePath));
    mapper.treeToValue(node, A.class);

  }

Then my file looks like this:

{"class":"B","filename":"myfile"}

I get the following error


-E- Caught exception; com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class A]

Thanks so so much for the help.

Best,
James

James Pinkerton

unread,
Jan 13, 2016, 5:52:26 PM1/13/16
to jackson-user
OK! I solved half of the problem.

Turns out my super class A had getters and setters in it involving maps and I didn't realize I had to annotate everything with @JsonIgnore.

How do I make the default turn off getters and setters and constructors unless specifically marked for de-serialization?

Second part of the problem:

I now have this working with the following decorator:


@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="class")
@JsonSubTypes({@Type(value = B.class, name = "B")})

I would like to just say:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")

or

@JsonTypeInfo(use=JsonTypeInfo.Id.MINIMAL_CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")

I ran this with MINIMAL_CLASS provided ".B" as the value to "class".

I got the following error:

-E- Caught exception; java.lang.IllegalArgumentException: Invalid type id 'my.path.to.bclass.is.this.B' (for id type 'Id.class'): no such class found

In reality "my.path.to.bclass.is.this" is my actual path.

So this is really weird: Jackson found the full path from ".B" but then says the class could not be found. Do you know what the issue is here?

All the best,
James

James Pinkerton

unread,
Jan 13, 2016, 6:01:13 PM1/13/16
to jackson-user
One more detail: using Class.forName("my.path.to.bclass.is.this.B") has no problem.

James

Tatu Saloranta

unread,
Jan 14, 2016, 6:52:29 PM1/14/16
to jackso...@googlegroups.com
On Wed, Jan 13, 2016 at 2:52 PM, James Pinkerton <james.c....@gmail.com> wrote:
OK! I solved half of the problem.

Turns out my super class A had getters and setters in it involving maps and I didn't realize I had to annotate everything with @JsonIgnore.

How do I make the default turn off getters and setters and constructors unless specifically marked for de-serialization?

There are a few ways; simplest would be to change Visibility Levels (minimum required to make getter/setter/field/ctor "visible" for introspection).
There is @JsonAutoDetect for individual classes; but ObjectMapper also has `setVisibility(...`) methods to change global defaults.
Those are often lowered, for example to require ALL properties to be annotated; or to raise visibility of fields (and lower getter/setter).
 

Second part of the problem:

I now have this working with the following decorator:


@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="class")
@JsonSubTypes({@Type(value = B.class, name = "B")})

I would like to just say:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")

or

@JsonTypeInfo(use=JsonTypeInfo.Id.MINIMAL_CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")

I ran this with MINIMAL_CLASS provided ".B" as the value to "class".

I got the following error:

-E- Caught exception; java.lang.IllegalArgumentException: Invalid type id 'my.path.to.bclass.is.this.B' (for id type 'Id.class'): no such class found

In reality "my.path.to.bclass.is.this" is my actual path.

So this is really weird: Jackson found the full path from ".B" but then says the class could not be found. Do you know what the issue is here?


No, that does sound odd. Minimal path is calculated from class name of the base type with @JsonTypeInfo annotation, and it would be possible that was is considered the base type could differ between serialization, deserialization; this could cause issues.
But if name displayed is as expected, this is probably not the issue here.

As to subtype naming: it is possible to register subtypes programmatically, by using SimpleModule (or any module but that's easiest), methods "registerSubtypes(...)".
This would let you avoid subtype annotation, which is in the wrong direction (that is, it's nasty thing to have to add).

But class name (full or partial, latter assuming base types match) should of course work; you should not have to use logical name if you do not want to.

-+ Tatu +-
Reply all
Reply to author
Forward
0 new messages