views:

436

answers:

7

Is there way to get properties files as strongly typed classes? I guess there are code generators but doing it with annotations would be much cooler.

What I mean is;

foo.properties file
keyFoo = valuefoo
keyBar = valuebar

maybe with

@properties(file="foo.properties")
class foo { }

becomes

class foo {
  String getKeyFoo() { }
  String getKeyBar() { }
}

if not shall I start an open source project for that?

ADDITION TO QUESTION;

Think we have a foo.properties file with let say more than 10 entries; and think it is used as a simple configuration file. What I believe is that this configuration entries should be provided as a configuration class with related getXXX methods to other parts of the design. Then rest of the system accesses the configuration via provided class instead of dealing with key names and don't need to bother where configuration comes. Then you can replace this class with a mock when you are testing callers and dependency to file system goes away. On the other hand it is really nice to get all entries in a strongly typed fashion.

So this issue is a code generation issue behind the scenes, it is nothing related to runtime. But code generation with an external something instead of annotations didn't seemed nice to me. Although I am not very much familiar with annotations, I guess this could be achieved (but I'll keep in mind that annotations can not generate classes as McDowell points)

A: 

If you want to do it statically, its a code generation problem that may be solved quite easily (for each item in file, produce a new getXXX method).

But if you want this at runtime, then you have the problem of having your code referencing method that did not exists at compile time; I don't think it can be done.

(Note that if you are looking for a project idead, the reverse, having an interface with accessor method and annotation, and an implementation generated at runtime, that relies on the annotated methods, can be done.)

penpen
Yes, it can be done--Java is a highly dynamic language, and you can spit out and modify classes at will. The question is "how much effort is required?"
Jonathan Feinberg
Of course, it is always possible to generates an object from the conf file, but without knowing the methods in advance, you won't be able to use it without resorting to reflection or things like this, and that makes this far less interesting.
penpen
@Jonathan: IMO, the real question is "what is the point?" since as @penpen points out you can only call the novel getXXX methods using reflection (or from other generated code).
Stephen C
+3  A: 

There is a somewhat similar project for doing configuration as statically typed files. It requires to declare an interface, but it fills in the implementation itself:

public interface AppConfig extends Config {
    long getTimeout ();
    URL getURL ();
    Class getHandlerClass ();
}
Avi
+1  A: 

The Annotation Processing Tool (apt) cannot modify classes (though it can create new ones). In order to modify the class at compile time, you'd probably need to edit the AST (as Project Lombok does). The simplest approach would probably be to generate the classes and then use the generated library as a dependency for other code.

McDowell
+2  A: 

There are countless of framework that achieve that for XML with various degree of configuration needed. The standard one bundled with Java is JaxB but it is not exactly a one liner xml persistence framework ...

The problem is that using properties file will only works better than XML (or JSON, ...) on the most trivial classes. When the class become a bit more complex, the properties file will become a nightmare. Another problem is that with trivial classes - there is not much difference between Xml and properties.

That means that the scope of the project will be rather limited. Mostly useful for project having loads of simple properties files.

In big application I worked with, strongly-type reading of properties file is done quite often using a simple factory-method.

 Foo foo = Foo.loadFrom("foo.properties");

 class Foo {
    static Foo loadFrom(String fileName) {
         Properties props = new Properties();
         props.load(...);

         Foo foo = new Foo();
         foo.setKeyFoo(props.get("KeyFoo"));
         ...
         return foo;
    }
   ...
 }
vdr
Example is good, this can be easily generated right?
erdogany
Probably or use reflection at runtime to load object dynamically: you can read annotation (available from the Class, Method and Field objects) and get/set properties dynamically (using apache common-beans can help you there). Try to keep it simple though if you have little config. For loads of config, Xml brings you structure, validation and documentation (in XSD), ...
vdr
+1 for JAXB. I've switched to it for my configurations. Also forced me to clean up my config / state distinction.
Ondra Žižka
+2  A: 

Something like JFig (ugly IMO), Commons Configuration or EasyConf?

Pascal Thivent
OT: Interesting: Although there are many libraries for reading properties, none of them provides ordered iteration - so I can't get the properties in the order they are defined in the file. So I extended Properties and delegated all Map methods to a ListOrderedMap.
Ondra Žižka
A: 

The OP would like to map a property file to a Java API such that each named property in the file corresponds to a similarly named getter method in the API. I presume that an application would then use this API to get property values without having to use property name strings.

The conceptual problem is that a property file is fundamentally not a statically typed entity. Each time someone edits a property file they could add new properties, and hence change the "type" of the property file ... and by implication, the signature of the corresponding API. If we checked that there were no unexpected properties when the Java app loaded the properties file, then we've got an explicit dynamic type-check. If we don't check for unexpected (e.g. misnamed) properties, we've got a source of errors. Things get even messier if you want the types of property values to be something other than a String.

The only way you could do this properly would be to invent the concept of a schema for a property file that specified the property names and the types of the property values. Then implement a property file editor that ensures that the user cannot add properties that conflict with the schema.

And at this point we should recognize that a better solution would be to use XML as the property file representation, an XML schema driven editor for editing property files, and JAXP or something like it to map the property file to Java APIs.

Stephen C
I didn't get what exactly you mean by "and hence change the "type" of the file" ... But I guess what you are worrying is different data types in the file? If so; for this case return types are always String... So adding a new entry to the file will cause generator to generate a new accessor method...
erdogany
@erdogany: No. I'm talking about the names of the properties changing. If you read the question, you'll see that the OP wants to map each property to a distinct getter method whose name is derived from the property name.
Stephen C
+1  A: 

Yet another way is to use a data binding framework that does this. Even one that does not seem to directly support that could work: for example, Jackson JSON processor would allow this to be done by something like:

ObjectMapper m = new ObjectMapper(); MyBean bean = m.convertValue(properties, MyBean.class); // (note: requires latest code from trunk; otherwise need to write first, read back)

which works as long as entries in Properties map match logical bean properties, and String values can be converted to matching underlying values.

StaxMan