Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursive @JsonUnwrapped (child with same type) fail: "No _valueDeserializer assigned" #383

Closed
tdavis opened this issue Jan 8, 2014 · 9 comments
Milestone

Comments

@tdavis
Copy link

tdavis commented Jan 8, 2014

Consider the following POJO:

public class RecursivePerson {

  private String name;
  private int age;
  private Gender gender;
  @JsonUnwrapped(prefix="child.") private RecursivePerson child;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public Gender getGender() {
    return gender;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }

  public RecursivePerson getChild() {
    return child;
  }

  public void setChild(RecursivePerson child) {
    this.child = child;
  }

}

When attempting to deserialize JSON:

{ "name": "Bob", "age": 45, "gender": 0, "child.name": "Bob's kid", "child.age": 15, "child.gender": 0 }

The deserialization fails at "child.age", with the following trace:

java.lang.IllegalArgumentException: No _valueDeserializer assigned
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.hubspot.rosetta.beans.RecursivePerson["child.age"])
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:2711)
    at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:2637)
    at com.hubspot.rosetta.RosettaMapper.mapRow(RosettaMapper.java:73)
    at com.hubspot.rosetta.RosettaMapperTestCase.map(RosettaMapperTestCase.java:155)
    at com.hubspot.rosetta.RosettaMapperTestCase.mapWithRecursiveNested(RosettaMapperTestCase.java:127)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No _valueDeserializer assigned
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.hubspot.rosetta.beans.RecursivePerson["child.age"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:700)
    at com.fasterxml.jackson.databind.deser.impl.FailingDeserializer.deserialize(FailingDeserializer.java:29)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:525)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:293)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:525)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
    at com.fasterxml.jackson.databind.deser.impl.UnwrappedPropertyHandler.processUnwrapped(UnwrappedPropertyHandler.java:62)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithUnwrapped(BeanDeserializer.java:497)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:263)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:2706)
    ... 28 more

I know this has something to do with the fact that the root object and "child" are of the same type; if the types are different it works fine.

Using Jackson 2.3.1

cowtowncoder added a commit that referenced this issue Jan 12, 2014
@cowtowncoder
Copy link
Member

Added the unit tests under 'failing', problem can be reproduced. Not sure why initialization isn't handled, but at least can verify eventual fix with the test now.

@cowtowncoder
Copy link
Member

I tried again to figure out this problem, but without success. I can see that the deserializer is missing in the end, but not how or why; the problem is related to recursive nature of unwrapper, but exactly how is unclear.

@cowtowncoder
Copy link
Member

I also wonder if this is even supportable: I can see that serialization works, and prepends prefixes as expected. But since the way deserializers is created is to statically create new unwrappers, solving initial problem might just lead into infinite recursion. Then again, since serialization does work (which is actually surprising :) ), perhaps this is doable.

@tdavis
Copy link
Author

tdavis commented Apr 10, 2014

Yeah, I think the fundamental issue is that it needs a deserializer for
RecursivePerson in order to deserialize the child, but it ran into
that requirement while building said deserializer.

Given that this is only an issue with JsonUnwrapped, is it possible
to make that variation less greedy? By which I mean, I can only assume
nested deserialization works properly because the deserializion process
operates breadth-first rather than depth-first: by the time it's ready
to deserialize "child" it already knows how to deserialize that
type. Not necessarily so when it goes to deserialize "child.",
though! I would assume serialization works similarly to nested
deserialization since there's no such thing as an "unwrapped" bean.

Then again, these assumptions could be wrong, in which case I remain
confused ;)

Tatu Saloranta [email protected] writes:

I also wonder if this is even supportable: I can see that serialization works, and prepends prefixes as expected. But since the way deserializers is created is to statically create new unwrappers, solving initial problem might just lead into infinite recursion. Then again, since serialization does work (which is actually surprising :) ), perhaps this is doable.


Reply to this email directly or view it on GitHub:
#383 (comment)

@cowtowncoder
Copy link
Member

Well, recursive serializers and deserializers work fine, in general -- there is explicit handling of this case so that construction is separate from resolution of handlers (serializers/deserializers) for fields and contents. But apparently handling of unwrapping for deserialization causes some linkage to be unbound (as unwrapped handler is typically copy of original thing, and perhaps this happens around resolution), leaving null. Question then if and how to make things still work...

@artur-devs
Copy link

Any updates on this issue? Possible work arounds ?

@cowtowncoder
Copy link
Member

@artur-devs No updates; not sure if anything can be done about this. For now you can consider combination of @JsonUnwrapped and recursive dependency to be unsupported.

@cowtowncoder cowtowncoder changed the title "No _valueDeserializer assigned" with JsonUnwrapped; "child" with same type Recursive @JsonUnwrapped (child with same type) fail: "No _valueDeserializer assigned" Oct 5, 2016
@cowtowncoder cowtowncoder added this to the 2.9.0 milestone Mar 26, 2017
@tdavis
Copy link
Author

tdavis commented Mar 27, 2017

Thanks for the fix @cowtowncoder!

@cowtowncoder
Copy link
Member

@tdavis better late than never! Thank you for reporting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants