Jonathan Chan
Jonathan Chan

Reputation: 2399

How to make this "cleaner"

Here is my problem.

I have a bunch of Configuration classes that get serialized by Gson. They're all located in one directory, and the serialization/deserialization processes are similar enough that I felt I should move the code up into parent classes.

I eventually came up with this (I feel it is horribly contrived):\

FooConfiguration.java:

package com.bar.foo;

import java.io.File;
import java.io.IOException;

public interface FooConfiguration {
    /**
     * Saves the configuration object to disk
     * @param location the location to save the configuration
     */
    public void save(File location) throws IOException;
}

FooConfigurationAbstract.java:

package com.bar.foo;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

import com.google.gson.Gson;

public abstract class FooConfigurationAbstract implements FooConfiguration {
    File location;
    Gson gson;

    @Override
    public void save(File location) throws IOException {
        FileUtils.writeStringToFile(location, gson.toJson(this), "utf-8");
    }
}

FooConfigurationImpl.java:

package com.bar.foo;

- snip imports -

public class FooConfigurationImpl extends FooConfigurationAbstract {

    /**
     * Whether or not the we should use the new Bar feature
     */
    @Expose
    public Boolean useBar = false;

    - snip more configuration values -
}

FooConfigurationFactory.java:

package com.bar.foo;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class FooConfigurationFactory<T extends FooConfiguration> {
    public static Gson gson = new GsonBuilder()
            .setPrettyPrinting()
            .excludeFieldsWithoutExposeAnnotation()
            .create();
    public Class<T> clazz;
    public File basePath;

    public FooConfigurationFactory(File basePath, Class<T> clazz) {
        this.basePath = basePath;
        this.clazz = clazz;
    }

    public T load(String location) throws IOException {
        return this.load(location, FooConfigurationFactory.gson);
    }

    public T load(String location, Gson gson) throws IOException {
        return gson.fromJson(
                FileUtils.readFileToString(
                    new File(this.basePath, location), "utf-8"),
                this.clazz);
    }
}

Example Usage:

this.config = new FooConfigurationFactory<FooConfigurationImpl>(this.configDir, FooConfigurationImpl.class).load("config.json");

I feel like this is the most ugly thing I have seen in my whole life. Is my approach simply wrong, or is there a better way to do it?

Upvotes: 4

Views: 290

Answers (1)

axtavt
axtavt

Reputation: 242786

  • You can simplify the hierarchy by moving save to a separate class. (I don't think that saving configuration to disk is a responsibility of the configuration itself.)
  • Do you actually need generic configuration factory? You can simplify usage syntax by using generic methods instead of generic class.

.

public class FooConfigurationService {
    ...
    public void save(File location, FooConfiguration configuration) { ... }    
    public <T extends FooConfiguration> T load(File location, Class<? extends T> clazz) { ... }
}

...

FooConfigurationFactory factory = ...;
this.config = factory.load(location, FooConfigurationImpl);    

Upvotes: 1

Related Questions