12

I'm writing a java application that contains a lot of savable settings. Basically my config structure looks like this:

Config
|_ game 1
   |_ Game name: blah...
   |_ Player name: alice
   |_ Player name: bob
   |_ other settings...
|_ game 2
   |_ Game name: hah
   |_ Player name: alice
   |_ Player name: bob
   |_ other settings...
|_ game n....

You got the idea. I tried use xml but working with dom4j is a pain especially there are a lot of child nodes with the same name in different and same parent nodes and I need to change them a lot. So far the most hassle-less way I discover is use a plain text file like

[Game 1]
Game name: blah
Player name: alice
Player name: bob
...

[Game 2]
...

But I feel like this is very rudimentary. So what is the best or standard practice in industry for maintaining config files in java?

EDIT : I'd like the solution to be portable, like copy a file from one computer to another will not break the program. (Sorry forget mention this ahead.)

YankeeWhiskey
  • 1,522
  • 4
  • 20
  • 32

4 Answers4

5

The best way to store settings/preferences in java is to use the Preferences API.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
2

You should have used automatic marshaller to write your XML file. A few years ago, I used CastorXML but today, there are probably more modern APIs to that purpose.

With this API, you basically :

  • Store all your config in a simple POJO
  • Instantiate a Marshaller
  • Call marshaller.write(MyConfig)

When you want to load your config :

  • Instantiate an Unmarshaller
  • call Marshaller.read(yourFile)

You can describe the XML mapping in a configuration file or use a default Marshaller (1 attribute ~ 1 XML tag)

It is that simple.

EDIT:

After a search in this thread, JAXB specification came after the first realease of CastorXML and the Sun implementation of JAXB seems now to be a standard for Java <-> XML mapping.

Community
  • 1
  • 1
Arnaud Denoyelle
  • 29,980
  • 16
  • 92
  • 148
  • The deal breaker here is that I have a lot of attributes with the same name, like the `player name`. So when I want to change `Alice` to `Leo`, I want to make sure that it doesn't overwrite `Bob` here. Can CastorXML guarantee that? Thanks. – YankeeWhiskey Jul 11 '13 at 12:14
2

Consider using YAML to define your configuration, it's much less verbose compared to XML, for example:

games:
  - name: 'game 1'
    players: ['Bob', 'Alice']
    ...
  - name: 'game 2'
    players: ['Bob', 'Alice']
    ...

You can then use the Jackson library with the YAML extension to interact with the configuration, for example to parse the configuration:

File configFile = new File("...");
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Configuration config = mapper.readValue(configFile, Configuration.class);
Jonathan
  • 20,053
  • 6
  • 63
  • 70
  • YAML is at least very portable between different stacks. And this was one of the authors requisits. – nialloc May 18 '21 at 10:00
1

Check out Apache Commons Configuration.

It provides good support for hierarchical configurations.

XMLConfiguration config = new XMLConfiguration("games.xml");
String gameName = config.getString("game1.name");
List<Object> playerNames = config.getList("game1.players.player.name");
// ...
config.setProperty("game1.name", "Space Invaders"); // update game name
config.addProperty("game1.players.player(-1).name", "ted"); // add new players
config.addProperty("game1.players.player(-1).name", "carol"); 
config.clearTree("game1.players.player(1)"); // remove a player

// Or with XPath 
config.setExpressionEngine(new XPathExpressionEngine());
config.addProperty("game1/players player/name", "ted"); 
config.addProperty("game1/players player/name", "carol"); 
config.clearTree("game1/players/player[2]");
Anthony Accioly
  • 21,918
  • 9
  • 70
  • 118