While reading through Stackoverflow, I came up to this interesting question: Java Properties File binding to Java Interface. The idea is simple but quite helpful. Basically we create an interface like:
interface LoginConstants extends Constants {
@DefaultStringValue("Welcome to my super app")
@Key("appDescription")
String appDescription();
@DefaultStringValue("Ok")
@Key("okButtonLabel")
String okButtonLabel();
}
Code language: Java (java)
And whenever we want to use constant in our application, we simple use loginConstant.appDescription(). Our application framework creates a dynamic proxy implementation for this interface. All we have to do is just to call the method and we get the value either from property file or default one. So below is the sample code: So basically you create an interface with relevant methods and annotate them with @Key, @DefaultStringValue annotations.
Disclaimer: This by no means should be used in Production. The code is just for reference. A lot more optimizations can be done in the below code. Below is the sample Java code:
Main.java
package net.viralpatel;
import net.viralpatel.annotations.DefaultStringValue;
import net.viralpatel.annotations.Key;
interface LoginConstants extends Constants {
@DefaultStringValue("Wellcome to my super app")
@Key("appDescription")
String appDescription();
@DefaultStringValue("Ok")
@Key("okButtonLabel")
String okButtonLabel();
}
public class Main {
public static void main(String[] args) {
LoginConstants constants = DynamicProperty.create(LoginConstants.class);
System.out.println(constants.appDescription());
System.out.println(constants.okButtonLabel());
}
}
Code language: Java (java)
Also the property file in background that we load is config.property
okButtonLabel=This is OK
Just execute the Main java class, following output will be displayed:
Output:
Wellcome to my super app
This is OK
Code language: JavaScript (javascript)
So now the magic code. Well nothing is magical here. Just plain Java Dyna proxy using Reflection API
DefaultStringValue.java
package net.viralpatel.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultStringValue {
public String value();
}
Code language: Java (java)
Key.java
package net.viralpatel.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {
public String value();
}
Code language: Java (java)
DynamicProperty.java
package net.viralpatel;
import java.lang.reflect.Proxy;
public class DynamicProperty {
public static < T extends Constants > T create(Class < T > clazz) {
T object = (T) Proxy.newProxyInstance(clazz
.getClassLoader(), new Class[] {
clazz
},
new Handler(clazz));
return object;
}
}
Code language: Java (java)
Handler.java
package net.viralpatel;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import net.viralpatel.annotations.DefaultStringValue;
import net.viralpatel.annotations.Key;
public class Handler implements InvocationHandler {
Object obj;
public Handler(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
String key = null;
String defaultValue = null;
try {
Annotation[] annotations = m.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Key) {
key = ((Key)annotation).value();
} else if (annotation instanceof DefaultStringValue) {
defaultValue = ((DefaultStringValue)annotation).value();
}
}
String ret = PropertyLoader.get(key);
return (null == ret) ? defaultValue : ret;
// result = m.invoke(obj, args);
} catch (Exception e) {
// We could also put some code here if we want to do
// anything special in case an Exception is thrown from
// the inside of invoked method.
throw e;
}
}
}
Code language: Java (java)
Constants.java
package net.viralpatel;
public interface Constants {
//marker
}
Code language: Java (java)
PropertyLoader.java
package net.viralpatel;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertyLoader {
private static Properties prop = null;
public static String get(String key) {
if (null == prop) {
init();
}
return (String) prop.get(key);
}
private static void init() {
prop = new Properties();
InputStream in = Properties.class
.getResourceAsStream("/net/viralpatel/config.properties");
try {
prop.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code language: Java (java)
Dynamic_Property_Java_Proxy.zip (12 KB)
Update Moved the code to Github for further development: github.com/viralpatel/dynaproperty
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
View Comments
That's a good start, the design shall be improved, I have a couple of good ideas, we should think to start a little project on github.
Sounds great... I will create a repo, commit the code and invite you for changes.
I would like to consider the CDI as http://stackoverflow.com/questions/13861005/java-properties-file-binding-to-java-interface/13876367#13876367
nice.
i will watch and star you repo ~~~
Hi.
at the end I implemented my own version since I needed to have full code coverage (doing TDD) and more functionalities (like the @Sources annotation)
So, sorry for not contributing to your implementation. I wanted also to start fresh.
I released under BSD license. The 1.0 has been released today.
Here is the website: http://lviggiano.github.com/owner/
Regards,
Luigi