Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Attempted to serialize ... Forgot to register a type adapter?"

Tags:

json

android

gson

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?

like image 216
Ilya Gazman Avatar asked Mar 21 '15 21:03

Ilya Gazman


2 Answers

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"
    }
}
like image 88
json1 Avatar answered Oct 19 '22 00:10

json1


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

like image 21
Andyccs Avatar answered Oct 18 '22 22:10

Andyccs