Git Product home page Git Product logo

Comments (12)

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
Extra info on the deserializing:
json = {"id":123,"thing":"AZ"}

Map<String, Object> decoded = gson.fromJson(data, new TypeToken<Map<String,
Object>>() {}.getType());

produces a map with: {id=java.lang.Object@e6612c, thing=java.lang.Object@d704f0}
(seems to be instances of Object with no data)

Original comment by azeckoski on 15 Sep 2008 at 1:29

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
First off, I'd like to start with some background information.  When you are 
defining
types (or local variables) that have type parameters, the JVM drops the actual 
type
parameters and associates everything as "Object".  This is known as "type 
erasure". 
In order for a Java Program to retrieve the actual type parameters at run-time, 
you
need to leverage the TypeToken object (this methodology was established by 
GUICE ---
see
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/TypeLiter
al.html).

Originally, we implemented Gson so that it could "serialize" these kinds of 
objects
without requiring the use of TypeToken; however, deserializing it back into the 
real
object requires it since the JSON output has no type information in it.  As 
well,
with this approach, it meant you were serializing the "real" object which meant 
that
some fields on the real object would be added to the JSON output.  Therefore, 
if you
had a List<A> and added both A and B objects (i.e. B extends A) some objects 
would
expose extra fields in the output.  We decided to take the more explicit route 
and
force the client to provide us the type parameters of the top-level object that 
is
being serialized.

The common use of a Map or List is that you populate the List with the same 
object
types.  Passing in Object means that you can add any instance of a class that 
you
desire to the data structure.  I know there are exceptions to this best 
practice, but
we do not want to implement this corner case scenario.  Instead, if you really 
do
want to use a list of Objects, then do as the exception message says and write a
"custom" (de)serializer (you can bind it specifically to a Map<String, Object> 
and
have the default Gson map serializer handle everything else).

As for a Map of Maps (i.e. Map<String, Map<String, Integer>>) this is already
supported and works well as long as you pass in the actual type object (i.e. new
TypeToken<Map<String, Map<String, Integer>>>() {}.getType())

Here's an example:
public static void main(String[] args) {
  Type mapType = new TypeToken<Map<String, Map<String, Integer>>>() {}.getType();
  Map<String, Map<String, Integer>> map = new HashMap<String, Map<String, Integer>>();
  Map<String, Integer> value1 = new HashMap<String, Integer>();
  value1.put("lalala", 78);
  value1.put("haha", 9999);
  map.put("id", value1);

  Map<String, Integer> value2 = new HashMap<String, Integer>();
  value2.put("nahhd", 121112);
  value2.put("uuywss", 19987);
  map.put("thing", value2);

  Map<String, Integer> value3 = new HashMap<String, Integer>();
  map.put("other", value3);

  Gson gson = new Gson();
  String json = gson.toJson(map, mapType);
  System.out.println(json);

  Map<String, Map<String, Integer>> deserializedMap = gson.fromJson(json, mapType);
  System.out.println(deserializedMap);
}

=========== OUTPUT ===========
{"thing":456,"id":123}
{"other":{},"thing":{"nahhd":121112,"uuywss":19987},"id":{"lalala":78,"haha":999
9}}
{other={}, thing={nahhd=121112, uuywss=19987}, id={lalala=78, haha=9999}}


For now, I am closing this off as "Working as Designed".  Maybe I am not 
completely
following your issue and if that is the case, please start up a new discussion 
in our
Gson discussion group.

Thanks,
Joel

Original comment by [email protected] on 16 Sep 2008 at 8:57

  • Changed state: Invalid

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
We solved our problem by using a different library but I wanted to put a 
comment here
anyway.

So what happens if I want to do this?
Map<String, Number>
or
Map<String, Serializable>

(it seems to fail)

It seems that this is designed to only work for the basic case where I have 
really
simple and non-nested structures where all the beans are easily instantiable 
and not
superclasses. It is a shame that this is considered working as designed.

Original comment by azeckoski on 18 Sep 2008 at 9:01

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
I am glad to hear that you found something that works for you, but it's too bad 
you
are unable to use Gson.  I'd still like to follow up on this issue because it is
user's like yourself that will help to advance this library.

First off, are you serializing and deserializing an object of type Map<String,
Number>?  If it is serialization only, than that is a much "easier" problem to 
solve
because we have the runtime types.  As for "deserializing" this kind of object, 
we
have provided our clients with the concept of a custom "Type Adapter".  You 
should be
able to write a type as follows to get it to work with "Number":

  public static class NumberTypeAdapter 
      implements JsonSerializer<Number>, JsonDeserializer<Number>,
InstanceCreator<Number> {

    public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext
context) {
      return new JsonPrimitive(src);
    }

    public Number deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
        throws JsonParseException {
      JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
      if (jsonPrimitive.isNumber()) {
        return jsonPrimitive.getAsNumber();
      } else {
        throw new IllegalStateException("Expected a number field, but was " + json);
      }
    }

    public Number createInstance(Type type) {
      return 1L;
    }
  }

  public static void main(String[] args) {
    Map<String, Number> map = new HashMap<String, Number>();    
    map.put("int", 123);
    map.put("long", 1234567890123456789L);
    map.put("double", 1234.5678D);
    map.put("float", 1.2345F);
    Type mapType = new TypeToken<Map<String, Number>>() {}.getType();

    Gson gson = new GsonBuilder().registerTypeAdapter(Number.class, new
NumberTypeAdapter()).create();
    String json = gson.toJson(map, mapType);
    System.out.println(json);

    Map<String, Number> deserializedMap = gson.fromJson(json, mapType);
    System.out.println(deserializedMap);
  }

========== OUTPUT ==========
{"double":1234.5678,"float":1.2345,"int":123,"long":1234567890123456789}
{double=1234.5678, float=1.2345, int=123, long=1234567890123456789}


We should probably just include the above type adapter as a default in Gson and 
I
will discuss this with Inderjeet.  There is a bug, however, since you actually 
have
to specify a "instance creator" for this type of object (i.e. primitive), but I 
will
have that fixed by the next release.  You should be able to write something 
similar
as above for "Serializable".

I hope this information is helpful and thanks for the all the feedback on this 
library.

Original comment by [email protected] on 27 Sep 2008 at 8:32

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
I modify the MapTypeAdapter to match the jdk14's Map
======================================================
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext 
context) {
      JsonObject map = new JsonObject();
      //Type childType = new TypeInfoMap(typeOfSrc).getValueType();
      for (Iterator iterator = src.entrySet().iterator(); iterator.hasNext(); ) {
        Map.Entry entry = (Map.Entry) iterator.next();
        Object obj = entry.getValue();
        JsonElement valueElement = context.serialize(obj, obj.getClass());
        ---------------------------------------------------------------------modified
        map.add(entry.getKey().toString(), valueElement);
      }
      return map;
    }
--------------------------------------------------------------------------------

and then the map class can be used like this:
  HashMap aaaa = new HashMap();
  aaaa.put("aa", 1212);
  aaaa.put("bb", "fasdfa");
  System.out.println(gson.toJson(aaaa));
==========output=================
{"bb":"fasdfa","aa":1212}
=================================

It can run, good or bad? because there are lot's of  jdk14's source code in many
project's.

Original comment by [email protected] on 21 Oct 2008 at 9:53

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
Thanks for providing the code snippet. This will not work properly in case of 
genericized maps since in those cases it is important to use the type specified 
in 
the field declaration instead of the actual type. I have made similar fixes for 
Issue 
54 and 58 that I will apply in this case as well. 

Original comment by inder123 on 21 Oct 2008 at 3:32

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
I have fixed this issue in r277 

Now, you should be able to serialize raw maps. The deserialization continues to 
require parameterized type. 

Original comment by inder123 on 21 Oct 2008 at 10:41

  • Changed state: Fixed

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
Thank you for fixing this issue: 
In java land, you really shouldn't be instantiating Map<String, Object> but 
since
we're dealing with JSON world, it actually makes a lot of sense. 
Consider Map<String, Object> map;
map.put("field1", 123);
map.put("field2", "myfield2");

What is gson.toJson(map)???
It's a javascript object o where o.field1 is the number 123 and o.field2 is the
string myfield2!

Original comment by [email protected] on 22 Jan 2010 at 9:43

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
json convert to map<Integer,MyClass> it have problem !
how to  do ?

Original comment by [email protected] on 6 Mar 2010 at 6:43

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
If you do json eval() in javascript or python, you get a dictionary. Inside the 
dictionary, it has String/Number or nested dictionaries. eval doesnt expect 
these type declarations.
I would expect the same on static language as well - Maps with default Number 
(lossless datatype like Double) datatype for deserialization.

Original comment by [email protected] on 25 Jun 2010 at 6:12

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
Hi demograp,

Did you forget to implement a default constructor for MyClass ?
It was my case, and I solved it doing this.

Hope it helps.

Original comment by [email protected] on 6 Aug 2010 at 2:45

from gson.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 8, 2024
I faced similar problems. Easiest solution for me was wrapping the desired map 
in a wrapper object and passing that to gson. I guess in the end that just 
boils down to be the same as providing the TypeToken, but it is a much more 
straightforward solution for those who want a quick fix.

Original comment by [email protected] on 1 Sep 2011 at 12:23

from gson.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.