0

I have a concrete class called "Clerk" that implements an interface called "Worker". I want to deserialize my Clerk object and store it into a Worker object, just like we can normally do if I had this:

Worker clerkWorker = new Clerk("abc", "alice white");

Only instead I have the clerk json that I want to deserialize and store into clerkWorker:

{
  "uid": "1a-2wq"
  "name": "Maryanne Chen"
}

The interface:

public interface Worker {
  int getUID();
  String getName();
  void work();
}

The class implementing it:

private class Clerk implements Worker {
  int uid;
  String name;

  public Clerk(id, fullname) {
    uid = id;
    name = fullname;
  }

  public void work() {
    System.out.println("Clerk is processing files");
  }
}

Following the second solution described here: Using Gson with Interface Types I copied RuntimeTypeAdapterFactory locally to use it:

RuntimeTypeAdapterFactory typeFactory =     
RuntimeTypeAdapterFactory.of(Worker.class, "type");
typeFactory.registerSubtype(Clerk.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeFactory).create();

final Reader r = getReader(jsonFile);
return gson.fromJson(r, typeToken.getType());

I've verified my getReader function is working. I get an exception:

"cannot deserialize interface Worker because it does not define a field named type".

Community
  • 1
  • 1
Marc
  • 219
  • 1
  • 15

2 Answers2

1

When you tell Gson to deserialize something with an interface type, it has to somehow figure out which implementing class it should use. It does this by checking a special field in the json data. When you call RuntimeTypeAdapterFactory.of(Worker.class, "type");, you are telling Gson that the field it should check to figure out which class it should use is named "type". When you then give it a chunk of json data that doesn't have that field, it complains.

To fix this, you will need to either add the "type" field to your json data, or tell Gson in the code to deserialize as Clerk, not Worker.

Douglas
  • 5,017
  • 1
  • 14
  • 28
  • I added private String type to Clerk.java, and in the json "type": "Clerk", same error – Marc Feb 15 '16 at 21:27
  • @Marc Try the fully qualified name ("your.package.here.Clerk") instead. I'd have to look more into the documentation to be sure, but that's my guess for what the default expects. – Douglas Feb 15 '16 at 21:32
  • no, you shouldnt need that, neither uid nor name did. I just want to deserialize json of Clerk type and store it in Worker type. – Marc Feb 15 '16 at 22:47
  • @Marc Did you try it, or just reject it? `uid` and `name` are fields in your class, `type` is identifying your class. They have different purposes and thus different expected contents. – Douglas Feb 15 '16 at 22:55
1

If Clerk is a Worker, then there shouldn't be any reason you can't just do exactly what you already showed with the constructor example.

Worker w = (new Gson()).fromJson( jsonData, Clerk.class ) ;

I'm not sure why you'd want so much to cast upward like this right away, since anything that wants a Worker should be able to take the Clerk directly...

zerobandwidth
  • 1,213
  • 11
  • 18