I chose to take properties file for customization of some settings.
I use the following code to make a Properties Object available in a class
Properties defaultProps = new Properties();
try {
FileInputStream in = new FileInputStream("custom.properties");
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
Do I have to add this to every class? Probably not because then every class would open a stream to this file.
But I'm not sure how to handle this properly.
Should I make a class MyProperties and instantiate it in whatever class needs properties?
Thanks in advance!
Once you initialized defaultProps, you can make its contents available to other objects in your app e.g. via a public static accessor method, e.g.:
public class Config {
private static Properties defaultProps = new Properties();
static {
try {
FileInputStream in = new FileInputStream("custom.properties");
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getProperty(String key) {
return defaultProps.getProperty(key);
}
}
This is the simplest approach, however it creates an extra dependency which makes unit testing harder (unless you provide a method in Config to set a mock property object for unit testing).
An alternative is to inject defaultProps (or individual configuration values from it) into each object which needs it. However, this may mean you need to add extra parameter(s) to lots of methods if your call hierarchies are deep.
If you only need one instance of your properties class you can use the singleton (anti?)-pattern.
It would look like a class like this:
public class MyProperties extends Properties {
private static MyProperties instance = null;
private MyProperties() {
}
public static MyProperties getInstance() {
if (instance == null) {
try {
instance = new MyProperties();
FileInputStream in = new FileInputStream("custom.properties");
instance.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return instance;
}
}
Why not use a static ResourceBundle ?
static final ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", currentLocale);
There's too little information to determine what the best way to handle this would be. You may want to expose it using an accessor, or pass it into each class that requires it. Alternatively, you may pull out the properties that each class needs and pass their values into the class's constructor.
Load the properties once using and store the Properties somewheres that others classes can pull from. If that is a MyProperties class that references a static variable somewhere that is fine.
This is a special case of making anything available globally. Using static methods is quite bad. A better but bad solution is using the sigleton pattern. Testing is the greatest problem here. IMHO, the best way is using Dependency injection, although it may be an overkill for small applications.
Since this information is static across all instances, I recommend implementing the Properties class as a singleton. By using the static initialization block method, you can have it load the file automatically when the program starts up.
public class Properties {
static {
try {
FileInputStream in = new FileInputStream("custom.properties");
load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected static void load(FileInputStream in) {
// existing load functionality here
}
}
You are still going to need an internal storage mechanism and accessor mechanism. These should also be marked static.
Rather than loading properties in every class. Load it somewhere around main() and pass it to other classes via their constructors.
Don't share them globally.
- Difficult to test
- Against the abstraction (Global access, DAO can access user settings. it should be prevented by passing only what it needs.. not everything)
- Classes lie what they need
Related
I need your advice about the best way to retreive config data which is stored within a java properties file from jersey web services to use them in several DAO classes called by those web services.
The solution that I implement is as follow:
create a java properties file and put in it all properties that I need
all the java properties file in an application listener and put properties in servletcontext attribute
in a web service, I retreive properties by injecting an instance on servletContext using #Context annotation and I pass them to any DAO function's methodes that need them.
So is it a good approach? If not, could you suggest me another solution?
instead of putting individual property as attribute to context put property object in context and from that prop object get the properties where required.
Why not using a Singleton class in which you read your propertie file ,
and then create an applicationLister by implmenting ServletContextListener#contextInitialized method and call getInstance of your class (this step is not mandatory , so you can left it, it's just to instantiate the singleton at the start of the app container ),
Adter in your whole project just call the satic method YouClass.getInstance() and acces your Properties.
By example :
public class MyPropertieFileReader {
private static MyPropertieFileReader instance = null;
private Properties properties;
protected MyPropertieFileReader() throws IOException{
properties = new Properties();
properties.load(getClass().getResourceAsStream("path-to-property-file.properties"));
}
public static MyPropertieFileReader getInstance() {
if(instance == null) {
try {
instance = new TestDataProperties();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return instance;
}
public String getProperty(String key) {
return properties.getProperty(key);
}
}
In your WS , just call
MyPropertieFileReader.getInstance().getProperty("property-name");
hope this will help .
I would like to bind some parameters with guice in similar way that guice binds the unannotated Injector class to the calling injector instance for use with a provider.
In particular, on our project we have an object called the ResourceEnvironment, this object is effectively a wrapper on the method Class.getClassLoader().getResource(), enabling us to elegantly convert "com-paths" (class relative resource paths) into the resources they represent (FXML files, image files, etc). We use this to load resources that are deployed within our jar.
Right now, this code is repeated with a huge amount of frequency:
Class ClazzX{
private final ResourceEnvironment env;
#Inject
public ClazzX(ResourceEnvironment.Factory envFactory){
env = envFactory.create(this.getClass())
}
}
when what I would really like to do is much more simply:
Class ClazzX{
private #Inject ResourceEnvironment env;
}
but to do that, I would effectively need a provider:
binder.install(new Module(){
#Provides ResourceEnvironment getResourceEnv(Injector callingInjector){
Class targetClazz = callingInjector.getDependencyBeingResolved(); //not a real method
ResourceEnivonment.Factory factory = callingInjector.getInstance(RE.F.class)
return factory.create(targetClazz);
}
});
Is it possible to get some information about the type currently being resolved through the injector at runtime?
Using the custom injection of loggers as a template (https://github.com/google/guice/wiki/CustomInjections) it should be easy to implement a specific memberinjector that uses the declaring class as a source for the environment injection. From what I know, this requires a custom annotaion as well.
class ResourceEnvironmentMembersInjector<T> implements MembersInjector<T> {
private final Field field;
private final ResourceEnvironment env;
ResourceEnvironmentMembersInjector(Field field) {
this.field = field;
env = envFactory.create(field.getDeclaringClass());
field.setAccessible(true);
}
public void injectMembers(T t) {
try {
field.set(t, env);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
I know this would seem to be something blasphemic and it (may) break the singleton nature so, please, don't hurt me! I'm just asking.
Assuming that the example below is just a random situation (and actually MY SITUATION, coincidence? I don't think so...) my question is generic.
I've got a singleton class like this:
public class SingleSessionFactory {
private SingleSessionFactory() {
}
private static class SingleSessionHelper {
private static final SessionFactory SESSION_FACTORY = getSingleSession();
private static SessionFactory getSingleSession() {
if (SESSION_FACTORY == null) {
Configuration hConf = new Configuration();
//hibernate configuration I wish to set by an object or sth dynamic not hard-coded!
try {
return hConf.buildSessionFactory();
} catch (ExceptionInInitializerError ex) {
System.out.println(ex.getMessage());
}
}
return SESSION_FACTORY;
}
}
public static SessionFactory getInstance() {
return SingleSessionHelper.SESSION_FACTORY;
}
}
which instead of the line //hibernate config...bla bla bla & bla... i used to call the setProperty(..) and addAnnotatedClass(..) hard-coded.
I wish to know if it's good to use a custom property object (by instance: MyHibernateConfiguration class) to use inside my getSingleSession(), which inside some attribute to store Hibernate properties (as "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect") and annotated class. Injecting or passing or...whatever... in this way "all that things" could be passed dynamically and that would be veeeeeryveryvery cool, isn't it right?
Anyway:
Q: Is it possible?
A1: Yeah of course! And the bestt way to do that is...
A2: NO! This is madness! I'm gonna underrate this question and send you to hell! Muha-ha-ha-haaaa... (yeah, evil laugh...)
That's all folk!
I would like to create a proper properties management strategy in a java webapp that relays on google guice as a DI framework.
I would like to have a mechanism answering the following 3 requirements:
I would like to be able to inject properties using guice (#Named)
I would like to be able to access properties in a static way
The mechanism should support prioritization of properties, meaning that a property can be wrapped in the deployed war with a certain value but it can also be redundant in the target system level or local file system (of the target machine I deploy on), in such a case the value in the war will be overridden by the value that exists in the target machine.
I believe this is a standard requirement. Now, using guice standard binder I can easily get the first requirement but not the other two. To get the other two I created my own class that does the following:
Wraps and exposes the binding methods of guice (those that binds properties) For example:
public static void bindString(AnnotatedBindingBuilder<String> binder, String property, String defaultValue) {
binder.annotatedWith(Names.named(property)).toInstance(getProperty(property, defaultValue));
}
Where the getProperty method knows how to handle my properties (get the value from the war or system level) and exposes the properties statically as well.
So basically as long as I'm using this utility that I created for properties bindings I'm good, it covers all my requirements but once I use the standard guice bindings I'm losing the second and third requirement.
Is there a way to override guice bindings and get all those 3 requirements?
Once I had the same challange in a spring based app and was pretty easy. I implemented ApplicationContextInitializer with the following method:
#Override
public void initialize(ConfigurableWebApplicationContext ctx) {
PropertySource<Map<String, Object>> localProps = null;
try {
localProps = new ResourcePropertySource(new ClassPathResource(LOCAL_PROPERTIES_FILE_NAME));
} catch (IOException e) {
LOG.fatal("Could not load local properties from classpath " + LOCAL_PROPERTIES_FILE_NAME);
return;
}
LOG.info("Loaded configuration from classpath local file " + LOCAL_PROPERTIES_FILE_NAME);
ctx.getEnvironment().getPropertySources().addFirst(localProps);
}
so this gave me a way to add local properties with highest priority to my Environment. In case of overlap with war properties the local ones had higher priority. In addition I exposed my Environment statically so I has static access to my properties (for services that are not managed by the container, legacy mostly).
How can I achieve this with guice?
Unfortunately, I don't think that you are going to find anything that gives you a truly clean and satisfying implementation. Especially, I don't think that you will find anything that gives you exactly what you want without implementing at least portions of it yourself.
If I had those needs, I would make sure that my injector is created in a central InjectorFactory. If you require a large number of parameters from outside to create your injector, I would simply create it once at the very beginning of my application and then cache the injector into a static final field. This would make it available to a static method. I would bind my "fall-back" property loading to an explicit provider. That way, instead of using the standard Names.bindProperties(...) method, I would bind it directly to a Provider. This provider then implements the logic that is necessary to perform the fallback or to merge multiple property files. Having the injector cached to a static field means that I can call a static method to access properties from a global-context outside of my injected classes.
Using your own provider seems initially unpleasant, but can provide some additional benefits. For starters, you can implement your fallback strategy exactly how you want. Additionally, you can add additional behaviors such as auto-reloading your property files, etc (not shown in my code sample).
public class InjectorFactory {
private static Injector injector = null;
public static synchronized Injector getOrCreateInjector() {
if(injector == null) {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
Properties properties1 = createProperties("file1.properties");
Properties properties2 = createProperties("file2.properties");
Set<Object> propertyNames = new HashSet<Object>();
propertyNames.addAll(properties1.keySet());
propertyNames.addAll(properties2.keySet());
for (Object object : propertyNames) {
String propertyName = (String) object;
bind(String.class).annotatedWith(Names.named(propertyName)).toProvider(new StringProvider(properties1, properties2, propertyName));
}
}
private Properties createProperties(String propertyFileName) {
try {
InputStream stream = InjectorFactory.class.getResourceAsStream(propertyFileName);
try {
Properties properties = new Properties();
properties.load(stream);
return properties;
} finally {
stream.close();
}
} catch (IOException exception) {
throw new RuntimeException("Could not load properties file");
}
}
});
}
return injector;
}
public static String getProperty(String propertyName) {
return getOrCreateInjector().getInstance(Key.get(String.class, Names.named(propertyName)));
}
}
Given the above code and file1.properties:
property1=Property1Value
property2=Property2Value
And file.properties:
property2=IncorrectProperty2Value
property3=Property3Value
with the provider
public class StringProvider implements Provider<String> {
private Properties properties1;
private Properties properties2;
private String propertyName;
public StringProvider(Properties properties1, Properties properties2,
String propertyName) {
this.properties1 = properties1;
this.properties2 = properties2;
this.propertyName = propertyName;
}
public String get() {
if(properties1.containsKey(propertyName)) {
return properties1.getProperty(propertyName);
}
return properties2.getProperty(propertyName);
}
}
The following usage:
public class InjectorFactoryTest {
public static void main(String ... parameters) {
System.out.println(InjectorFactory.getProperty("property1"));
System.out.println(InjectorFactory.getProperty("property2"));
System.out.println(InjectorFactory.getProperty("property3"));
}
}
Outputs:
Property1Value
Property2Value
Property3Value
I need my Java app to read the config properties from a file and use them throughout the classes. I'm thinking of a separate class, that would return a map of property_key:property_value for each of the properties in the file. Then I would read the values from this map in other classes.
Maybe there are other, more commonly used options?
My properties file is simple and has about 15 entries.
Just use java.util.Properties to load it. It implements Map already.
You can load and get hold of the properties statically. Here's an example assuming that you've a config.properties file in the com.example package:
public final class Config {
private static final Properties properties = new Properties();
static {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
properties.load(loader.getResourceAsStream("com/example/config.properties"));
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static String getSetting(String key) {
return properties.getProperty(key);
}
// ...
}
Which can be used as
String foo = Config.getSetting("foo");
// ...
You could if necessary abstract this implementation away by an interface and get the instance by an abstract factory.