Reputation: 4151
I have an abstract class:
public abstract class Measurement {
String Name;
String Value;
abstract void setName(String name);
abstract Object getName();
abstract void setValue(String value);
abstract Object getValue();
@Override
abstract public String toString();
}
And several concrete versions such as this one:
public class BasicMeasurement extends Measurement {
//removed for brevity's sake
}
And finally, a Utility class for serializing to disk for storage
public class Config {
public List<Measurement> Measurements;
public HashMap<String,String> Items;
public Config(){
Measurements = new ArrayList<Measurement>();
Items = new HashMap<>();
}
}
I am using Gson to (de)serialize this Config class to disk and back. Serializing to disk works fine, but, deserializing explodes due to the abstract class.
So I have start to follow the directions here, when I realized that it will require some significant modification to work in my use case.
Q: What method(s) would be best to (de)serialize my config class that would 1. Not blow up and 2. Would not cause loss of information when deserializing (Even if it doesnt blow up, deserializing to type Measurement would cause loss of the specific concrete values)
Current Save Method
public boolean SaveSettings() {
try {
FileOutputStream fileOutputStream = mActivity.openFileOutput(SETTINGS_FILE_NAME, Context.MODE_PRIVATE);
this.json = gson.toJson(this.Config);
fileOutputStream.write(this.json.getBytes());
fileOutputStream.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Current Load Method
public static MeasureSettings LoadSettings(Activity activity) throws Exception {
MeasureSettings measureSettings = new MeasureSettings(activity);
measureSettings.json = measureSettings.getStringFromFile(SETTINGS_FILE_NAME);
if(measureSettings.json.length() != 0) {
measureSettings.Config = gson.fromJson(measureSettings.json, Config.class);
}
measureSettings.SaveSettings();
return measureSettings;
}
Upvotes: 1
Views: 1896
Reputation: 4151
So my assumptions were correct, the added hierarchy from my Config class did bjork the custom serializer/deserializer.
I was however able to work around the problem, and still use the custom deserializer.
DeSerializer - this is only used for the items in my ArrayList
@Override
public A deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("MyType").getAsString();
try {
// String thePackage = "com.onetwentyonegwatt.MeasurementLib";
return context.deserialize(json, Class.forName(type));
} catch (ClassNotFoundException e) {
throw new JsonParseException("Unknown element type: " + type, e);
}
}
Its usage here:
public static MeasureSettings LoadSettings(Activity activity) throws Exception {
MeasureSettings measureSettings = new MeasureSettings(activity);
measureSettings.json = measureSettings.getStringFromFile(SETTINGS_FILE_NAME);
if(measureSettings.json.length() != 0) {
JsonParser jsonParser = new JsonParser();
JsonObject o = (JsonObject)jsonParser.parse(measureSettings.json);
JsonElement items = o.get("Items");
measureSettings.Config.Items = gson.fromJson(items,measureSettings.Config.Items.getClass());
JsonElement measurements = o.get("Measurements");
for(JsonElement item : measurements.getAsJsonArray()) //Iterating the ArrayList values(As json array) here and then deserializing one by one.
{
// deserialize(item,Class.forName(item.getAsJsonObject().get("MyType").getAsString()),context);
String className = item.getAsJsonObject().get("MyType").getAsString();
Class<?> type = Class.forName(className);
Measurement l = (Measurement)measureSettings.gsonBuilder.create().fromJson(item,Class.forName(className));
measureSettings.Config.Measurements.add(l);
}
//measureSettings.Config = measureSettings.gsonBuilder.create().fromJson(measureSettings.json,Config.class);
}
measureSettings.SaveSettings();
return measureSettings;
}
Upvotes: 1