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?
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.
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
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.
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
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"
}
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With