Marc
Marc

Reputation: 219

Deserializing an object of a concrete type into an interface type

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".

Upvotes: 0

Views: 692

Answers (2)

zerobandwidth
zerobandwidth

Reputation: 1303

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...

Upvotes: 1

Douglas
Douglas

Reputation: 5087

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.

Upvotes: 1

Related Questions