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

Gson fails to parse simple map #501

Open
GoogleCodeExporter opened this issue Mar 19, 2015 · 16 comments
Open

Gson fails to parse simple map #501

GoogleCodeExporter opened this issue Mar 19, 2015 · 16 comments

Comments

@GoogleCodeExporter
Copy link

When parsing the following json with gson (using 2.2.2 from maven-central), 
gson (fromJson) throws an:

JsonSyntaxException: "duplicate key: null"

whereby the json is created by gson (toJson) itself.

Json:
{"appProperties":{"server.configuration.reset":"false","server.db.jndi":"testDB"
,"xml.basedata.list":"basedata.xml","server.configuration.cache":"false","xml.la
yout.list":"","server.rolemapper":"InsertionRoleMapper","xml.content.list":"data
.xml"}}

http://json.parser.online.fr/ validates the string as correct...

Original issue reported on code.google.com by phil...@meisen.net on 15 Feb 2013 at 12:04

@GoogleCodeExporter
Copy link
Author

I have the same issue, that is Gson.fromJson throws an JsonSyntaxException: 
"duplicate key: null"
whereby the json is created by Gson.toJson itself.

(I'm not posting the actual Json string because it may contain company 
information.)

Original comment by bpgergo on 5 Mar 2013 at 4:18

@GoogleCodeExporter
Copy link
Author

[deleted comment]

1 similar comment
@GoogleCodeExporter
Copy link
Author

[deleted comment]

@GoogleCodeExporter
Copy link
Author

I had the same problem but it turns out it was my fault - I had a map like this:

Map<Outcome, Integer> myMap

where Outcome is an enum. However in the enum, toString was not returning the 
name(). 

So GSON could write the JSON ok, but it could not deserialize it, because when 
it tried to create the enum, it didn't know how so it wrote a null, then when 
did this the second time it reported "duplicate key: null"

Original comment by mark.but...@oi-sys.com on 11 Jul 2013 at 4:22

@GoogleCodeExporter
Copy link
Author

I have this issue too. My object extended a LinkedHashMap and I could serialize 
just fine (it would fill in the "class":"my.obj.MyClass", but when reading in 
json with a class keyword, it would fail with the "duplicate key: class" error.

Does anyone know if there is a way to ignore class keywords when creating the 
object, or fail and ignore the keyword, yet build the rest of the JSON object? 

My toString() method for the object MyClass is this: return new 
Gson().toJson(this);
I instantiate it from a file using this: return new Gson().fromJson(json, 
MyClass.class);
(json is one line from the data file I'm reading in in a String format)

Original comment by Initial....@gmail.com on 23 Nov 2013 at 1:01

@GoogleCodeExporter
Copy link
Author

Hey guys, 

Anyone has any updates on this. We just hit this on production. We have a 
Map<Map<enum,Object>> and we got the same errors. Any workarounds ?

Original comment by shiv...@totvslabs.com on 8 Sep 2014 at 5:24

@GoogleCodeExporter
Copy link
Author

@shiv: Map<Map<enum,Object>> makes no sense. The fact that you're getting the 
same message doesn't imply you ran into the same issue. Possibly, there's no 
issue, ask on SO instead.

AFAIK using a Map as a key is a problem. Using an enum defining toString is a 
problem, too, as `toString()` gets used for serialization, but the 
deserialization uses `name()`. This is wrong and should be (or has already 
been?) fixed.

Original comment by Maaarti...@gmail.com on 11 Sep 2014 at 9:46

@GoogleCodeExporter
Copy link
Author

@Maaarti: I guess I didn't provide the full information. The real object that 
we convert back from json is: 
Map<String, List<Map<PassingParamEnum, Object>>>. And what we use to convert it 
is: 
Type mapType = new TypeToken<HashMap<String, List<Map<PassingParamEnum, 
Object>>>>()
        {
        }.getType();
        actualObject = gson.fromJson(theJsonString, mapType);

I am not using a map as a key. I am using a String as a key. I also have a LIST 
of a Map which is really where gson is giving us errors for Duplicate Keys. 

com.google.gson.JsonSyntaxException: duplicate key: PENDING_ACTION_ID

the PENDING_ACTION_ID is actually a key for this map: Map<PassingParamEnum, 
Object> and then a list of that Map is stored.

The weird thing is it doesn't happen all the times. Once a while it starts 
giving this error. And in the json string itself if you move around the key, it 
suddenly works. 

I am willing to provide the json string data where it SOMETIMES fails if anyone 
is interested in looking at it.

Original comment by shiv...@totvslabs.com on 26 Sep 2014 at 4:28

@GoogleCodeExporter
Copy link
Author

@shiv: I'd strongly suggest to ask on stackoverflow.com where you may get an 
answer withing a few minutes. This issue list is not particularly responsive 
and it may or may not be an issue. This very issue mixes multiple problems over 
more than one year and makes little sense (if any). Without your data, I can't 
tell more, but with them, someone on SO will.

Original comment by Maaarti...@gmail.com on 29 Sep 2014 at 6:50

@busylee999
Copy link

I faced the same trouble. But I figured out it was because of we have map<enum, T> and ones server started returns new enum type, we had not had yet, so it leaded to this error, two nulls as keys.

@perpetual-dork
Copy link

perpetual-dork commented Apr 20, 2019

I'm serializing a map.. the json object only has one key in it.
"map": { "string_key": 0 }

Every time I attempt to deserialize this, it throws this exception.

com.google.gson.JsonSyntaxException: duplicate key: string_key

@TheDoctorOne
Copy link
Contributor

TheDoctorOne commented Sep 1, 2021

Since issue is still open, i'm guessing its still here. Here is how i solved my case:
I had an issue with Map<enum, list> like everyone else. After seeing this issue and debugging realized it was because of the enum.
So I cast my Map<enum, list> to Map<Integer, list>. Then did my serialization / de-serialization.

Here is an example code, similar to mine. Changed variable names etc.

	public static <T extends Enum, V> Map<T, V> fromOrdinal(Map<Integer, V> ordMap, Class<T> enumClass) {
		Map<T, V> org = new HashMap<>();
		
		for(int ord : ordMap.keySet()) {
			org.put(enumClass.getEnumConstants()[ord], ordMap.get(ord));
		}
		return org;
	}
	
	public static <T extends Enum, V> Map<Integer, V> toOrdinal(Map<T, V> map) {
		Map<Integer, V> ord = new HashMap<>();
		for(T key : map.keySet()) {
			ord.put(key.ordinal(), map.get(key));
		}
		return ord;
	}

@eamonnmcmanus
Copy link
Member

I don't think there's enough information in this issue to be actionable. There may be more than one underlying issue, or there may be none and people are just not using the API right. (So there might be a documentation issue.)

If you have a problem that seems like this one, please show an exception backtrace and the code you are using to deserialize.

@TheDoctorOne
Copy link
Contributor

TheDoctorOne commented Sep 3, 2021

I don't think there's enough information in this issue to be actionable. There may be more than one underlying issue, or there may be none and people are just not using the API right. (So there might be a documentation issue.)

If you have a problem that seems like this one, please show an exception backtrace and the code you are using to deserialize.

Here is the exact code i am testing it right now with the latest version "2.8.8":

package net.mahmutkocas.dummy;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.*;

public class Main {

    public static void main(String[] args) {

        TestClass testClass = new TestClass();
        for(TestEnum s : TestEnum.values()) {
            testClass.typesMap.put(s, "test");
        }

        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.create();

        try {
            String json= gson.toJson(testClass);
            System.out.println(json); // Output is provided at below with backtrace.
            gson.fromJson(json, TestClass.class);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    public enum TestEnum {
        ENUM1,
        ENUM2,
        ENUM3,
        ENUM4;

        @Override
        public String toString() {
            return super.toString().toLowerCase(Locale.ENGLISH);
        }
    }


    public static class TestClass {
        public Map<TestEnum, String> typesMap = new HashMap<>();
    }

}

And here is the backtrace:

Output of the system.out : {"typesMap":{"enum2":"test","enum4":"test","enum1":"test","enum3":"test"}}

com.google.gson.JsonSyntaxException: duplicate key: null
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:190)
	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
	at com.google.gson.Gson.fromJson(Gson.java:932)
	at com.google.gson.Gson.fromJson(Gson.java:897)
	at com.google.gson.Gson.fromJson(Gson.java:846)
	at com.google.gson.Gson.fromJson(Gson.java:817)
	at net.mahmutkocas.dummy.Main.main(Main.java:22)

Hope it helps.
Note: This only happens if and only if when Enum's toString() method gets overriden and returning value does not equal to original name.

@eamonnmcmanus
Copy link
Member

Thanks @TheDoctorOne, that does look suspicious and we should look into it.

@eamonnmcmanus eamonnmcmanus reopened this Sep 10, 2021
@TheDoctorOne
Copy link
Contributor

TheDoctorOne commented Sep 10, 2021

Thanks @TheDoctorOne, that does look suspicious and we should look into it.

See #1950 , as far as i tested, it works. And should have backwards compatibility.

Edit: It checks on the highest level, where de-serialization done. It can be also done at serialization part which may be more convenient for future use. I don't know if that would be backwards compatible, if backwards compatibility matters to the project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants