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

Force root wrapping per class #1022

Open
cowtowncoder opened this issue Nov 26, 2015 · 12 comments
Open

Force root wrapping per class #1022

cowtowncoder opened this issue Nov 26, 2015 · 12 comments
Labels
most-wanted Tag to indicate that there is heavy user +1'ing action

Comments

@cowtowncoder
Copy link
Member

(note: moved from FasterXML/jackson-annotations#33 filed by @chrylis -- see there for longer discussion)


I'm working on mapping an external service that sends postbacks in wrapped JSON. I have set the @JsonRootName on the class and can read objects with a specially-configured mapper, but this wrapping behavior belongs to this service (i.e., a certain set of classes) specifically, and not to the overall system (Spring MVC, which expects a single mapping configuration).

Since it's known that this class will always need to be unwrapped, and request classes wrapped, it would be much clearer to be able to force root wrapping per class, perhaps with an alwaysWrap field on the @JsonRootName annotation. Is this a feasible feature?


@jam01
Copy link

jam01 commented Apr 6, 2017

Hey @cowtowncoder any news on this?

@cowtowncoder
Copy link
Member Author

@jam01 I haven't worked on this. And just so you know, whenever I do work on issues, I will add notes either directly or via references from commits, so asking for update is rarely if ever going to give different answer.

@cowtowncoder cowtowncoder added the 3.x Issues to be only tackled for Jackson 3.x, not 2.x label Nov 13, 2017
@cowtowncoder
Copy link
Member Author

Notes:

  • @JsonRootName has commented out "alwaysWrap" (but should be changed to OptBoolean to allow "use defaults")

@Masquerade0097
Copy link

@cowtowncoder I'm facing the same issue here . Any solution ?

@OndraZizka
Copy link

OndraZizka commented Jun 10, 2019

Is there any workaround for this? In #33 You mentioned JacksonAnnotationIntrospector, but I can't see a way to propagate any "don't wrap this one" to wherever that is needed.
Could you please suggest how this could be implemented? Or what's preventing it? Where the WRAPping happens? I could have a look at it.

@cowtowncoder
Copy link
Member Author

@OndraZizka I don't remember much more than the fact that it was not trivial to propagate. Indicating (perhaps via additional property for @JsonRootName) would be easy to add to AnnotationIntrospector, but question then is how behavior would be efficiently checked for reading and writing. You can follow the path via ObjectReader (and variants in ObjectReader / ObjectWriter) wrt existing SerializationFeature.WRAP_ROOT_VALUE / DeseriazationFeature.UNWRAP_ROOT_VALUE.

@OndraZizka
Copy link

OndraZizka commented Jun 10, 2019

I am looking at DefaultSerializerProvider. Jackson 2.9.9. At line 444, there is:

    } else if (rootName.isEmpty()) {
        wrap = false;

Which suggests that @JsonRootName("") could do it. But it doesn't. I didn't look closer how the name gets to that point.

Edit: I see. It's only in serializePolymorphic.

@OndraZizka
Copy link

OndraZizka commented Jun 10, 2019

Seems that the place to change is in RootNameLookup:

    // No answer so far? Let's just default to using simple class name
    if (name == null || !name.hasSimpleName()) {
        // Should we strip out enclosing class tho? For now, nope:
        name = PropertyName.construct(rootType.getSimpleName());
    }

And maybe PropertyName.NO_NAME could be used to pass the "no-root" flag.

Edit: So, if it could differentiate between PropertyName.DEFAULT_NAME and PropertyName.NO_NAME, it might be done relatively easily.
The question is then: Could the namespace be "" for that? Which is ugly. Or, it could be a special-purpose subclass, NowrapPropertyName, which the AnnotationIntrospector could return, and the DefaultSerializerProvider would then check simply using instanceof.

Is this solution viable?

@cowtowncoder
Copy link
Member Author

I don't think namespace can be used, as that is needed for XML. PropertyName is not just used for root names, so although I don't want to fully rule that out as a possibility, it also seems bit too hacky.

But changing the type of value stored in root-name cache in itself would be fine; that need not be PropertyName.
However, now... logic to even check if root wrapping is to be used relies on feature; if that is not enabled, no lookup is attempted. So it's not purely question of changing @JsonRootName but also changing that logic.

@OndraZizka
Copy link

Right. I would change the logic this way:

  • WRAP_ROOT_VALUE would become WRAP_ROOT_VALUE_BY_DEFAULT.
  • If that is enabled, then it would behave as now.
  • If that is disabled, then it would wrap only if @JsonRootName is present.
    Is there any use case for having @JsonRootName` and having wrapping disabled?

@OndraZizka
Copy link

OndraZizka commented Jun 10, 2019

Also, I think that the current implementation of wrapping into clasname by default default is a bit buggy.
When I have UNWRAP_ROOT_VALUE enabled, and in my Deserializer use jsonParser.readValueAsTree, I get this exception:

Root name 'Code' does not match expected ('JsonNode') for type [simple type, class com.fasterxml.jackson.databind.JsonNode]

Which I can't workaround no matter what I try, because it's happening internally.

I have created #2351, hope that makes sense.

@cowtowncoder
Copy link
Member Author

Ok, just to make sure: while it is possible to add new features (although I want to keep number limited since they need to fit in 32-bit int for now), we can not remove or rename existing ones (or change behavior), at least until 3.0.
So addition needs to work in fully backwards compatible manner.

Other than that, this approach could work.

Issue with reading trees is probably a bug (as per my notes, Tree Model should just skip wrap/unwrap handling altogether): wrapping/unwrapping specifically relates to Bean/POJO handling.
This can potentially be problematic if user calls readValue() with JsonNode (over explicit "read as tree" methods), probably need to check that.

@cowtowncoder cowtowncoder added most-wanted Tag to indicate that there is heavy user +1'ing action 2.14 and removed 3.x Issues to be only tackled for Jackson 3.x, not 2.x labels Jul 20, 2021
@cowtowncoder cowtowncoder removed the 2.14 label Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
most-wanted Tag to indicate that there is heavy user +1'ing action
Projects
None yet
Development

No branches or pull requests

4 participants