It's hard to answer this with the information provided. For instance, you say that you're "stringifying" the data, but you aren't saying what method you're using. Is there a library you're using? Is the string JSON, XML, or some other structured data?
I'll assume that you're using some type of structured data (for simplicity, let's say JSON using GSON or similar).
So at write time, you'll create and write a string
public void writeToFile(String filname, Object myObject) {
String serialized = new Gson().toJson(myObject);
try(FileOutputStreamoutputStream output =
openFileOutput(filename, Context.MODE_PRIVATE)
) {
output.write(s.getBytes());
} catch (Exception e) {
Log.e("MyApplication",
"Unable to write " + serialized + " to file " + filename + " with exception",
e
);
}
}
And at read time, you'll want to just read the data back. Well, that's pretty easy
public <T> T read(String filename, Class<T> clazz) {
String serialized = new Gson().toJson(myObject);
try (
BufferedReader reader = new BufferedReader(
new InputStreamReader(
openFileInput(filename, Context.MODE_PRIVATE)
)
)
) {
StringBuilder json = new StringBuilder();
String line;
while((line = reader.nextLine()) != null) {
json.append(line);
}
return new Gson().fromJson(json.toString, clazz);
} catch (Exception e) {
Log.e(
"MyApplication",
"Unable to read " + filename + " to class " + clazz.simpleName() + " with exception",
e
);
return null;
}
}
But wait, you said that you changed the name of a field. Well, the easiest solution is to just not have changed the name of said field. But this is the real world, there are business requirements, pompous developers who know more than their predecessors, or whatever. You inherited the code. I'm not going to blame you for this.
So, the next easiest solution is to keep older versions of your classes around. For instance, you could wrap your read function with
public <T> T readFromFile(String filename, Transformer<T> optimusPrime) {
for(Class clazz : optimusPrime.getSupportedClasses()) {
//TODO optimize this (haha, like that'll get prioritized)
Object o = read(filename, supportedIterator.next())
if(o != null) {
return optimusPrime.transform(o)
}
}
return null;
}
Where your transformer class has a collection of all the possible classes that could have ever been stored in the file (hopefully sorted from most to least likely), and a general method to translate between them. It would probably look something like this
public class OptimusPrime implements Transformer<Autobot> {
private final Map<Class, TransformMethod> transformations;
public OptimusPrime() {
transformations = new TreeMap<>;
transformations.put(Megatron.class, new MegatronTransform());
transformations.put(Starscream.class, new StarscreamTransform());
transformations.put(Shockwave.class, new ShockwaveTransform());
//Shhhh
}
@Override
public Collection<Class> getSupportedClasses() {
return transformations.keySet();
}
@Override
public Autobot transform(Object o) {
TransformMethod<Autobot> transformation = transformations.get(o.getClass());
return (transformation == null) ? null : transformation.transform(o);
}
}
And
public class MegatronTransform implements TransformMethod<Autobot> {
@Override
public Megatron transform(Object o){
return (Megatron) o;
}
}
So, it's doable, but your code base is going to inflate, and you'll never be able to get rid of all those old classes in your code unless you either give the user some error and recovery method, or you're 100% sure that no users have the legacy data type stored on their device.
What would be a much easier (more expensive) option would be to store the data inside of a versioned API somewhere in the "cloud." That way you can have control over the data and its storage mechanism.