johnzon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Markus Karg <k...@quipsy.de>
Subject AW: User Question: Complex Adapters
Date Tue, 01 Oct 2019 15:27:37 GMT
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 <rmannibucau@gmail.com> 
Gesendet: Dienstag, 1. Oktober 2019 16:50
An: dev@johnzon.apache.org
Betreff: Re: User Question: Complex Adapters

Le mar. 1 oct. 2019 à 16:36, Markus Karg <karg@quipsy.de> 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 <rmannibucau@gmail.com>
> Gesendet: Dienstag, 1. Oktober 2019 16:24
> An: dev@johnzon.apache.org
> 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 <karg@quipsy.de> 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
> >
> >
> >
>
Mime
View raw message