Romain,
thank you for this interesting analysis! In fact I think the cause is actually
more simple and has nothing to do with cardinality, Map or Map.Entry etc.: It
is impossible to use Adapters on the top level OR adapters must not adapt upon
custom types (even when they are mappable)!
Proof see below. Question: Is that wanted by JSON-B spec or is that a bug in
Johnzon?
public static void main(String[] a) {
// Should parse JSON to Foo, then map Foo to Bar, but actually tries to
parse JSON to Bar directly, IGNORING the mapper!
JsonbConfig jsonbConfig = new JsonbConfig().withAdapters(new
FooBarMapper());
Jsonb jsonb = JsonbBuilder.create(jsonbConfig);
System.out.println(jsonb.fromJson("{ }", Foo.class)); // works well :-)
System.out.println(jsonb.fromJson("{ }", Bar.class)); // FooBarMapper is
NOT invoked -> Johnzon tries to create Bar instance :-(
}
public static class Foo { }
@JsonbTypeAdapter(FooBarMapper.class) private static class Bar {
Bar(int jsonCannotCallThis) { }
}
public static class FooBarMapper implements JsonbAdapter<Bar, Foo> {
@Override public Foo adaptToJson(Bar obj) throws Exception { return new
Foo(); }
@Override public Bar adaptFromJson(Foo obj) throws Exception {return
new Bar(1); }
}
I know, I can solve with a Deserializer. What I like to reach is to clarify
whether this is a bug in Johnzon (so we need to fix it) or whether this is as
wanted by JSON-P spec, so we should improve the JavaDocs there. :-)
-Markus
-----Ursprüngliche Nachricht-----
Von: Romain Manni-Bucau <[email protected]>
Gesendet: Dienstag, 1. Oktober 2019 16:50
An: [email protected]
Betreff: Re: User Question: Complex Adapters
Le mar. 1 oct. 2019 à 16:36, Markus Karg <[email protected]> a écrit :
> Romain,
>
> thanks for your ideas. As always, they are very valueable. 😊
>
> I assume that a Deserializer would actually work and *workaround* the
> current problem (which is fine for now). But my question really is:
> Isn't the word "cardinality" missing in the Spec then? And what if I
> actually want to map a collection to an int by let's say return the
> count of ist entries... (yes, hypothethical, just to make you
> understand my point: this is nowhere forbidden by the spec)?
>
Well spec explains how a map is mapped not how a nested object of an object is
automatically mapped so it sounds explicitly not handled to me.
> The container level actually is there, but not visible to Johnzon: The
> adapter actually does the cardinality change in its *implementation*
> (not in its *declaration*), as it simply picks the first entry in the
> map. In fact I do not find anything in JSON-B spec nor JavaDocs that
> both sides of the adapter MUST have the same cardinality, as the spec
> and JavaDocs for adapters *just* say that any umappable class has to
> be adapted to "just some" mappable class (without a word about
> cardinality) -- and Map apparently *is* "just some" mappable class.
>
It is not needed but your Entry has no link with the json so it would fail
anyway.
Note that the underlying is not cardinality but object mapping (and 100% relies
on the signatures in jsonb - johnzon has a programmatic alternative but it is
not needed here).
I suspect here the map type is the issue since it is handled ad-hoc and
bypasses adapters.
We could add a toggle to disable that since spec does not say anything on that
but we would keep current behavior until the johnzon toggle is enabled for
compatibility reasons (we just did a 1.2, i prefer to avoid a 1.3 less than a
month after ;)).
> Wdyt?
>
> -Markus
>
>
> -----Ursprüngliche Nachricht-----
> Von: Romain Manni-Bucau <[email protected]>
> Gesendet: Dienstag, 1. Oktober 2019 16:24
> An: [email protected]
> Betreff: Re: User Question: Complex Adapters
>
> Hi Markus,
>
> Map does not match Map.Entry so it does not work ;)
>
> Semantically you miss a level of "container" (a map is a kind of
> List<Map.Entry> even if structurally it does not match).
> Also note that Map.Entry is modelized per its signatures as a
> {key:...,
> value: ....} and not as {key:value} as in a map.
>
> I guess a Deserializer can be closer than an adapter of what you are
> trying to do.
>
> Romain Manni-Bucau
> @rmannibucau <https://twitter.com/rmannibucau> | Blog <
> https://rmannibucau.metawerx.net/> | Old Blog <
> http://rmannibucau.wordpress.com> | Github
> <https://github.com/rmannibucau>
> | LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book <
> https://www.packtpub.com/application-development/java-ee-8-high-perfor
> mance
> >
>
>
> Le mar. 1 oct. 2019 à 16:17, Markus Karg <[email protected]> a écrit :
>
> > I’d be very very glad if you could answer a short user question I’m
> > completely stuck with. 😊
> >
> > Johnzon is able to parse JSON object into Java Map while respecting
> > custom
> > adapters:
> >
> > // Works well: Uses custom Adapter<UUID, String> Map<UUID, Foo> map
> > = jsonb.fromJson("{ \"" + uuid + "\": { \"name\":
> > \"Lala\" } }", new JohnzonParameterizedType(Map.class, UUID.class,
> > Foo.class));
> >
> > Now let’s assume we do not want to get a complete Map but just a
> > single Map.Entry, as we know for sure the JSON string only contains
> > exactly just one single key-value-pair:
> >
> > JsonbConfig jsonbConfig = new JsonbConfig().withAdapters(new
> > UuidAdapter(), new MapEntryAdapter<UUID, Foo>());
> >
> > // Fails with "Can't map Entry<UUID, Foo>"
> > Map.Entry<UUID, Foo> entry = jsonb.fromJson("{ \"" + uuid + "\": {
> > \"name\": \"Lala\" } }", new
> > JohnzonParameterizedType(Map.Entry.class,
> > UUID.class, Foo.class));
> >
> > public class MapEntryAdapter<K, V> implements
> > JsonbAdapter<Map.Entry<K,
> > V>, Map<K, V>> {
> > @Override public Map<K, V> adaptToJson(Entry<K, V> obj) throws
> > Exception { … }
> > @Override public Entry<K, V> adaptFromJson(Map<K, V> obj) throws
> > Exception { … } }
> >
> > Strange but true, this does not work but complains it cannot map
> > Entry<UUID, Foo> -- it seems it cannot „see“ the correctly
> > registered adapter (not even if I replace <K, V> by <UUID, String>
> > manually in the code).
> >
> > So the question is: Where is the fault? Did I try something (what?)
> > which is forbidden in JSON-B? Is this a bug in Johnzon?
> >
> > Actually I assume it is my personal fault (as so often), but I just
> > cannot see where… 😉
> >
> > Thanks a lot for your kind help!
> > -Markus
> >
> >
> >
>