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

RFE: per-property/per-class unwrapped de/serialization of single-element array/List/Set/Queue/Collection #611

Closed
ceefour opened this issue Nov 13, 2014 · 8 comments
Milestone

Comments

@ceefour
Copy link

ceefour commented Nov 13, 2014

This builds upon the work in https://jira.codehaus.org/browse/JACKSON-805

A feature to do this on a per-property or per-class (with inheritance) basis.

[JSON-LD|http://www.w3.org/TR/json-ld/] which is a W3C Recommendation, uses this convention where a singular property can be turned into array (retaining the original name) in order to have multiple cardinality.

However, some properties, like http://schema.org/offers are always rendered as array.

While the proper way to handle such cases is a full-blown JSON-LD processor (JSON-LD has lots more features and is very flexible), for common use cases people might just want to use Jackson to read/write JSON-LD, and having this capability will be good.

An annotation is required, probably @JsonCollectionAsScalar (or @JsonScalar? or @JsonSingleElement?), with two fields:

  • boolean value = true -> deserialize scalar as collection. This is most important as it allows to read most JSON-LD effortlessly.
  • boolean serialize = true -> serialize single-element collection as scalar. If I were a JSON-LD writer, I'd set serialize=false in order to make it much easier (albeit longer JSON path) for naive clients to read, since the JSON will have a rigid schema.

If boolean is ambiguous then can also use enum.

Note that behavior for nested collection is undefined (and probably should be an error), so the contents of collection must be either primitive or a non-collection object. (note that some objects may be Iterable, which should be okay, still treated as JSON object)

@cowtowncoder
Copy link
Member

I think this makes sense; many/most Jackson features have both general defaults, and local overrides, sometimes even two levels (per-class, per-property).
As to nested feature, that's an interesting question, and may have to be "implementation dependant", that is, actual behavior may need to be partly based on how unwrapping/wrapping itself is handled.

One question here is the annotation to use. Possible alternative could be to add a new property for @JsonFormat, but I don't know if that'd be any easier.

One more thought is whether there's need for actual Jackson LD datatype module. While it might seem like an overkill for just this feature, if there are related things that would need tweaks or additions, I would prefer building new stuff outside of the core databind.

@markwoon
Copy link
Contributor

A Jackson LD module would definitely be of interest. I'm using Jackson to output JSON-LD as well and we've had to use a few hacks to get it to work smoothly.

@ceefour
Copy link
Author

ceefour commented Nov 13, 2014

I'd prioritize the annotation first... so it can be used as quick solution, although cannot parse full JSON-LD.

@ansell develops https://github.com/jsonld-java/jsonld-java project which uses Jackson 2.3.3 currently.

I for one would be happy if there'd be a JSON-LD module for Jackson (easy to use like JodaModule) that supports "native" binding of JSON-LD structure. For example, instead of binding field names... we bind Linked Data names (i.e. http://schema.org/offers). @JsonTypeInfo will be enhanced to support Linked Data classes. Same goes for representing URIs, enums, etc. But this would be a major effort...

@cowtowncoder
Copy link
Member

My point here is that if annotation did not have to be added in core Jackson (annotations or databind), that might be preferable regardless. Adding a module & project is easy, so there isn't much cost from our side.

Having said that, I am ok with this as a databind feature. I am just worried about simple one-off annotations, and would want to limit number of core annotations.

@tea-dragon
Copy link
Contributor

This was a feature I had to cut when I switched over to jackson for most of the back-end processing. However, during the time I supported per property overrides, I never ran into a case where allowing coercion during deserialization but always writing back out as arrays was undesirable behavior. I was considering making that the default anyway.

That seems to be the behavior you are suggesting in your example, except that now you would be able to enforce stricter parsing on other fields. Maybe I am undervaluing deserialization strictness, but that doesn't seem like a huge gain at first glance.

FWIW, I configured this setting as a boolean annotation field named autoCollection that lived in my equivalent to JsonProperty, but I only supported deserialization, so it was a little more straightforward. That seemed fine. Another kinda neat option you could try is to create some wrapping/delegating (de)serializers, set them up with existing annotations, and then use JacksonAnnotationsInside to create an alias. Probably breaks on some edge case though.

@cowtowncoder
Copy link
Member

@tea-dragon One possibility would, in fact, be to add support via AnnotationIntrospector first, for 2.5, and not (yet?) add actual core annotation for indicating it. Maybe I should start from this end.
This would also allow different approached between reading/writing (accepting/producing) unwrapped single-element arrays; whether it's both-of-nothing, or separate settings; either way, having two new methods in AnnotationIntrospector

@tea-dragon
Copy link
Contributor

Starting with AnnotationIntrospector sounds reasonable to me. In many ways, that class is more important than the annotations themselves. If this was my request, then that would be more than sufficient. Since I have no use for these features though, usability in terms of "not having to know what AnnotationIntrospector is" may or may not be important for solving their immediate need.

@cowtowncoder
Copy link
Member

This was actually implemented via @JsonFormat annotation extension:

FasterXML/jackson-annotations#43

and I think specifically with JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED.
There are couple of other relevant features, and new ones may be added as needed.
Functionality was added in Jackson 2.6.

If features are missing, please re-file a new issue, as that makes it easier to keep track of work and related versions.

@cowtowncoder cowtowncoder added this to the 2.6.0 milestone Nov 5, 2015
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

4 participants