How to convert HashMap to JSON using Gson.
class ClassData {
public String jsonString;
public Class classType;
}
HashMap<String, ClassData> map = new HashMap<>();
void convert(){
new Gson().toJson(map); // throws
}
I am getting the next exception
Attempted to serialize java.lang.Class: java.lang.String. Forgot to
register a type adapter?
You need to implement your own custom serializer for ClassData, and then register it to your Gson Builder.
public class ClassDataSerializerExample {
static class ClassData {
public String jsonString;
public Class classType;
public ClassData(String jsonString, Class classType) {
this.jsonString = jsonString;
this.classType = classType;
}
}
static class ClassDataSerializer implements JsonSerializer<ClassData> {
@Override
public JsonElement serialize(ClassData src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.jsonString);
}
}
public static void main(String[] args) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(ClassData.class, new ClassDataSerializer());
HashMap<String, ClassData> map = new HashMap<>();
map.put("key", new ClassData("key", String.class));
Gson gson = gsonBuilder.create();
String json = gson.toJson(map);
System.out.println(json);
}
}
Output: {"key":"key"}
Read more: https://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Serializer
My approach works for Gson 2.3.1 with Java 1.7, can't guarantee it will work with Android.
The problem lies within the variable classType
, since Gson can't process the type Class
as it is. So we have to create a TypeAdapter for Class.
public class ClassTypeAdapter extends TypeAdapter<Class<?>> {
@Override
public void write(JsonWriter jsonWriter, Class<?> clazz) throws IOException {
if(clazz == null){
jsonWriter.nullValue();
return;
}
jsonWriter.value(clazz.getName());
}
@Override
public Class<?> read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
}
Class<?> clazz = null;
try {
clazz = Class.forName(jsonReader.nextString());
} catch (ClassNotFoundException exception) {
throw new IOException(exception);
}
return clazz;
}
}
To make it work you'll need a TypeAdapterFactory.
public class ClassTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
if(!Class.class.isAssignableFrom(typeToken.getRawType())) {
return null;
}
return (TypeAdapter<T>) new ClassTypeAdapter();
}
}
And register the TypeAdapterFactory to your Gson Builder.
gsonBuilder.registerTypeAdapterFactory(new ClassTypeAdapterFactory());
AFAIK you have to use a TypeAdapterFactory. A directly registered TypeAdapter
gsonBuilder.registerTypeAdapter(Class.class, new ClassTypeAdapter());
seems to be ignored when an object of type Class
is encountered.
Gson transforms both the HashMap
and Java class instances to JSON objects.
Example:
{
"hash_key_1": {
"jsonString": "json_string_instance_1",
"classType": "my.class.Name1"
},
"hash_key_2": {
"jsonString": "json_string_instance_2",
"classType": "my.class.Name2"
}
}