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