views:

84

answers:

3

I have a custom INIFile class that I've written that read/write INI files containing fields under a header. I have several classes that I want to serialize using this class, but I'm kind of confused as to the best way to go about doing it. I've considered two possible approaches.

Method 1: Define an Interface like ObjectPersistent enforcing two methods like so:

public interface ObjectPersistent
{
    public void save(INIFile ini);
    public void load(INIFile ini);
}

Each class would then be responsible for using the INIFile class to output all properties out to the file.

Method 2: Expose all properties of the classes needing serialization via getters/setters so that saving can be handling in one centralized place like so:

public void savePlayer(Player p)
{
    INIFile i = new INIFile(p.getName() + ".ini");
    i.put("general", "name", p.getName());
    i.put("stats", "str", p.getSTR());

    // and so on
}

The best part of method 1 is that not all properties need to be exposed, so encapsulation is held firm. What's bad about method 1 is that saving isn't technically something that the player would "do". It also ties me down to flat files via the ini object passed into the method, so switching to a relational database later on would be a huge pain.

The best part of method 2 is that all I/O is centralized into one location, and the actual saving process is completely hidden from you. It could be saving to a flat file or database. What's bad about method 2 is that I have to completely expose the classes internal members so that the centralized serializer can get all the data from the class.

I want to keep this as simple as possible. I prefer to do this manually without use of a framework. I'm also definitely not interested in using the built in serialization provided in Java. Is there something I'm missing here? Any suggestions on what pattern would be best suited for this, I would be grateful. Thanks.

+2  A: 

Since you don't want (for some reason) to use Java serialization, you can use XML serialization. The simplest way is via XStream:

XStream is a simple library to serialize objects to XML and back again.

If you are really sure you don't want to use any serialization framework, you can of course use reflection. Important points there are:

  • getClass().getDeclaredFields() returns all fields of the class - both public and private
  • field.setAccessible(true) - makes a private (or protected) field accessible via reflection
  • Modifier.isTransient(field.getModifiers()) tells you whether the field has been marked with the transient keyword - i.e. not eligible for serialization.
  • nested object structures may be represented by a dot notation - team.coach.name, for example.

All serialization libraries are using reflection (or introspection) to achieve their goals.

Bozho
Personally I feel if you don't have a long tree structure of data, INI files provide a more clear and easily viewed way of representing data in key value pairs within a header. I prefer to use my INIFile class and not a framework as noted in the original post.
suinswofi
@suinswofi see the update
Bozho
I guess I'm referring more towards the pattern of serialization. I can see reflection getting really messy trying to check types and calling the correct put() for whatever primitive type within my INIFile.I want to know how frameworks like XStream do what they do. I don't see a particularly clean way of doing it. Either way it seems like you're breaking some rule, whether that's the single responsibility rule, or encapsulation, or whatever other convoluted guideline for OOP.
suinswofi
you just call "put" - no checks for primitives, they are autoboxed.
Bozho
and, @suinswofi , XStream uses reflection.
Bozho
A: 

This is a job for the Visitor pattern.

EJP
+1  A: 

I would choose Method 1.

It might not be the most object oriented way, but in my experience it is simpler, less error-prone and easier to maintain than Method 2. If you are conserned about providing multiple implementations for your own serialization, you can use interfaces for save and load methods.

public interface ObjectSerializer
{
    public void writeInt(String key, int value);
    ...
}

public interface ObjectPersistent
{
    public void save(ObjectSerializer serializer);
    public void load(ObjectDeserializer deserializer);
}

You can improve these ObjectSerializer/Deserializer interfaces to have enough methods and parameters to cover both flat file and database cases.

msell