3
\$\begingroup\$

I have a settings.txt file with the following format:

property=value
another_property=value

category.sub_category.property_name=value

And a Settings class that reads the properties out of this file and uses reflection to assign values to the corresponding fields within the class and it's subclasses:

public final class Settings {
    private Settings(){}

    public static void loadSettingsFile(){

        String dir = System.getProperty("user.dir") + "/settings.txt";
        try {
            List<String> lines = Files.readAllLines(Paths.get(dir));
            for(String str : lines){
                String[] property = str.split("=");
                if(property.length == 2)
                    setProperty(property[0], property[1]);
            }
        } catch (Exception e) {
            System.out.println("Settings file not found");
        }
    }

    public static void setProperty(String name, String value){
        try {
            @SuppressWarnings("rawtypes")
            Class target = Settings.class;
            int lastDot = name.lastIndexOf('.');

            if(lastDot != -1){

                String classPath = Settings.class.getPackage().getName();
                classPath += ".Settings$" + name.substring(0, lastDot).replace('.', '$');

                target = Class.forName(classPath);
                name = name.substring(lastDot + 1);
            }

            Field property = target.getField(name);

            switch (property.getType().getName()) {
            case "boolean":
                property.setBoolean(null, value.equals("true"));
                break;
            case "int":
                property.setInt(null, Integer.parseInt(value));
                break;
            case "double":
                property.setDouble(null, Double.parseDouble(value));
                break;
            case "java.lang.String":
                property.set(null, value);
                break;
            case "[Ljava.lang.String;":
                property.set(null, value.split(","));
                break;
            case "[I":
                String[] values = value.split(",");
                int[] ints = new int[values.length];
                for(int i = 0; i < ints.length; i++)
                    ints[i] = Integer.parseInt(values[i]);
                property.set(null, ints);
                break;

            default:
                System.out.println("Could not set property '" + name + "' - unsupported field type: " + property.getType().getName());
                return;
            }

        } catch (NoSuchFieldException | ClassNotFoundException e) {
            System.out.println("Can't find or access property: " + name);
        } catch (IllegalAccessException | SecurityException e) {
            System.out.println("Can't set property '" + name + "' to " + value);
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("Can't set property '" + name + "' to " + value);
        }
    }






    /*------------------------------
       settings fields start here
    ------------------------------*/

    public static String mode = "training AI";

    public static class map{
        private map(){}

        public static int width = 35;
        public static int height = 30;
        public static int random_walls = 10;
    }

    public static class training{
        private training(){}

        public static String algorithm = "genetic";
        public static String[] ann_files = null;

        public static boolean override_ann_file_settings = false;
        public static String sensory_input = "basic";
        public static int smell_precision = 1;
        public static boolean interfering_outputs = false;

        // more settings...
    }

    // more subclasses containing settings...
}

I find it convenient to be able to access these settings OOP style from anywhere in my program, I prefer it over a Settings.get(String name) solution because that way the IDE shows me what settings there are so I don't have to remember all their names.

Are there any disadvantages to this solution?

Also I'm not sure about the naming convention, should I make the setProperty(...) method convert property names to match normal Java naming convention or is it ok as it is now?

category.sub_category.property_name
convert name to:
Settings.Category.SubCategory.propertyName
\$\endgroup\$
2
\$\begingroup\$

You should always use curly braces even if your loop/if statement contains 1 line.

You're catching all Exceptions and assuming it's due to the file not being found. You should be catching FileNotfoundException instead. Alternatively you could check if the File is found or not.

What if the property format is invalid? E.G 2 '=' signs or 0. Currently you wouldn't throw or log any error and silently ignore it. I'd suggest at least LOGGING something

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.