Parsing JSON into Map with FlexJSON

2019-08-05 04:08发布

问题:

I am trying to parse a JSON structure similar to this one:

    {
 "cars": {
  "112": {
   "make": "Cadillac",
   "model": "Eldorado",
   "year": "1998"
  },
  "642": {
   "make": "Cadillac",
   "model": "Eldorado",
   "year": "1990"
  },
  "9242": {
   "make": "Cadillac",
   "model": "Eldorado",
   "year": "2001"
  }
 }}

I have a CarEntity class defined with makeName,model,year attributes defined and accessible via setters/getters.

I am trying to deserialize this JSON like this:

    Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String, CarEntity>>()
   .use("cars.values", Map.class)
   .deserialize(json);

and it doesn't work :( It does deserialize it but not into Map<String, CarEntity> but rather into deep Map(something like Map<String, Map<String, Map<String, String>>> )

What am I doing wrong?

回答1:

You're problem is your json has two maps. One which contains the 'cars' key, and one that contains the actual CarEntity. Unfortunately, you can't refer to a single key within a Map and assign types on just that key at this time. Generally setting types on values for collections refers to all values within the collection. You don't need to specify the types for the first Map that contains the "cars" key since it will deserialize it by default.

Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String,Map<String, CarEntity>>>()
    .use("values.values", CarEntity.class )
    .deserialize(json).get("cars");

The path 'values.values' refers to the outer Map's values then traversing the next map values are all CarEntity instances.

I've considered changing the path expressions to be more expressive allowing you to target a single value in a collection, but this increases overhead of evaluating them and being backwards compatible is a challenge.



回答2:

You are most likely being bitten by Java Type Erasure: JSON library in question does not know type you want; all it sees is equivalent of Map. So you must specify at least value type somehow. Hopefully FlexJSON documentation points out how.

Alternatively you may be able to sub-class HashMap into your own type (MyEntityMap extends HashMap), since then type information can be inferred from generic super type; and passing MyEntityMap.class would give type information that most JSON libraries can use (Jackson and GSON at least).

If these do not work, Jackson and GSON libraries can handle this use case easily; both have methods to specify generic types for deserialization.



回答3:

Just add one more call to get("cars") like:

Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String, CarEntity>>()
   .use("cars.values", Map.class)
   .deserialize(json).get("cars");

jSon string was probably serialized from a variable cars typed as Map<String, CarEntity>