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

Map deserialization doesn't use Adapter and generates runtime exception on access #253

Open
nickarls opened this issue Mar 15, 2019 · 3 comments
Labels
bug Something isn't working right

Comments

@nickarls
Copy link

Given a simple POJO "Person" with a String attribute "name" and a test like

public static void main(String[] args) { String json = "{\"foo\" : \"bar\"}"; Map<Person, String> map = JsonbBuilder.create().fromJson(json, new HashMap<Person, String>() {}.getClass().getGenericSuperclass()); map.keySet().forEach(Person::getName); }

I end up with
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to test.Person at java.util.HashMap$KeySet.forEach(HashMap.java:933) at test.Test.main(Test.java:14)

If I register an adapter for Person, it is never called. How can a String even fit into the Person map key and only be detected at runtime?

@bravehorsie
Copy link
Contributor

bravehorsie commented Mar 15, 2019

Looks like a reopen of #110.
In runtime the <Person> signature is not present, so any value fits. However Yasson should avoid class cast failing earlier and also tell something more specific in this case.

A bit of a background on current implementation and why your adapter is not used:
JSON doesn't allow anything else than string to be used as a key in a json object structure.
Serializing Maps with any different key type than String has to end up as a String key mapping.
Currently we use String.valueOf (toString) for serialization of any key type other than string.

This can be customized registering adapter / (de)serializer for whole map type for example:

public class PersonKeyMapSerializer implements JsonbSerializer<Map<Person,String>> {}

Adapters / serializers registered directly for the map key type are not used during Map processing. I am not all against it, but if we do want to introduce it, we would still have to check that to/from type cannot be anything else than string for a key.

@bravehorsie bravehorsie added the bug Something isn't working right label Mar 15, 2019
@nickarls
Copy link
Author

Does Gson or Jackson etc have any workaround for this case?

@siaspa
Copy link

siaspa commented Jun 21, 2019

Maybe I should open a new issue, but my one is similar to this...

I have a Map<NOT_A_STRING, ?> and I would like to have a json like this:

  "items": [
     "item" {
         "key": { ... },
        "value": { ... }
     },
     "item" {
         "key": { ... },
        "value": { ... }
     },
  ]

I tried to build a MapAdapter, but was only able to get the content of "key" and "value" as a string, using jsonb.toJson(e.getValue()...)

Then I tried to use serializers. In this case the @JsonbTypeSerializer can't be used because in the MapSerializer the default constructor is missing and a constructor with a builder is required.

So I've added it to the configuration, it was a little bit complex because of the Builder requirement.

Unfortunately the MapSerializer is based on Map<String, ?> maps. So I've inherited from it and then I've overridden the serializeInternal method. I was not able to serialize the key and the value object, because a class cast exception was thrown.

If it could be useful, I'll build a small project just to better clarify the point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working right
Projects
None yet
Development

No branches or pull requests

3 participants