Class usage inside class static initialization block - java

Probably it is discussed somewhere but I failed to find it.
I need to load class properties (java.util.Properties) inside class static initialization block. This is to make possible to access some class general options even without its objects creation. To do so I need appropriate Class object. But of course access to such Class object fails on null object. Something like this.
Class Name {
private static Properties properties;
static {
Name.properties = new Properties();
Name.properties.load(Name.class.getResourceAsStream("Name.properties"));
}
}
Any idea how to handle this situation?
UPDATE:
It was resource name (should be "/Name.properties" for my case). Everything else was OK.
+1 for all meaningful answers from me and ... don't forget to check operations one by one :-).

properties field must be static. And before load you need to initialize static variable with proeprties = new Properties() after that you can invoke load

Declare properties as static and initialize
static Properties properties;
or
static Properties properties = new Properties();
and static block should be
static {
try {
properties = new Properties(); //if you have not initialize it already
Name.properties.load(Name.class.getResourceAsStream("Name.properties"));
} catch (IOException e) {
throw new ExceptionInInitializerError(e); //or some message in constructor
}
}
You need to catch IOException while loading properties file

Final code based on all suggestions is like this:
Class Name {
private static final Properties properties = new Properties();
static {
try {
InputStream stream = Name.class.getResourceAsStream("/Name.properties");
if (stream == null) {
throw new ExceptionInInitializerError("Failed to open properties stream.");
}
Name.properties.load(stream);
} catch (IOException e) {
throw new ExceptionInInitializerError("Failed to load properties.");
}
}
}

Related

Testing a method by overriding a private class variable as an initial step before refactoring

What is the best way of writing a unit test for a method, such as my setProperties (see below), that uses a private configuration variable (config). I tried but failed to override it using reflection and Makito, but without success. I realize that changing the design to make the code easier to test is best, but I want to created some unit tests before I refactor the code.
public class MainClass {
private final java.lang.String config = "app.properties";
public TestClass() {
try {
setProperties();
} catch (Exception e) {
e.printStackTrace();
}
}
public void setProperties() throws Exception {
try {
InputStream input = new BufferedInputStream(new FileInputStream(config));
..
..
} catch (Exception exception) {
throw exception;
}
}
}
Do refactor a tiny bit by extracting a method with a parameter that takes an input stream. Call this new method (probably package-protected) from the old one. Write tests against the new method. Then do more refactorings.
This is an indication of a broken design; don't hard-code things like this. Better yet, determine what the appropriate responsibility for this class is, and, in decreasing order of preference:
pass in an object with the configuration properties, strongly typed
pass in a Map with the configuration properties
pass in an InputStream for the properties file
As File objects are never available from a jar, you shouldn't ever make interfaces like this more specific than InputStream or Reader, so that you can always pass in streams from your jar classpath.
So you can use Properties class in Java for this. Please have a look at this code.
public class PropertyUtil {
private static Properties prop;
private static Logger logger = Logger.getLogger(PropertyUtil.class);
private PropertyUtil() {
}
public void setProperty() {
String filePath = System.getenv("JAVA_HOME") + "/lib" + "/my_file.properties";
prop = new Properties();
try (InputStream input = new FileInputStream(filePath)) {
prop.load(input);
} catch (IOException ex) {
logger.error("Error while reading property file " + ex);
}
}
public static String getProperty(String key) {
if (prop.containsKey(key)) {
return prop.getProperty(key);
} else {
return null;
}
}
public static <T> T getProperty(String key, Class<T> claz) {
if (claz.getName().equals(Integer.class.getName())) {
return claz.cast(Integer.parseInt(prop.getProperty(key)));
}
if (claz.getName().equals(Long.class.getName())) {
return claz.cast(Long.parseLong(prop.getProperty(key)));
}
if (claz.getName().equals(Boolean.class.getName())) {
return claz.cast(Boolean.parseBoolean(prop.getProperty(key)));
}
if (claz.getName().equals(Double.class.getName())) {
return claz.cast(Double.parseDouble(prop.getProperty(key)));
}
if (claz.getName().equals(String.class.getName())) {
return claz.cast(prop.getProperty(key));
}
return null;
}

Loading Property File from Filesystem in Jboss Fuse / Karaf throws Nullpointer

I try to load a property file in Java running on JBossFuse/karaf.
The file is located at $[karaf.home]/etc/bean.properties
The Code is able to load properties inside the bundle fine, but now I try to exclude the properties from the project itself and the code throws a Nullpointer-Exception.
The Path is properly resolved on my development machine as
C:\Users\someone\devstudio\runtimes\jboss-fuse-6.3.0.redhat-135\etc\bean.properties
The property-File can be loaded in the blueprint-XML to configure beans, but to access the bean my code needs the CamelContext. As I have some static codeblocks that are accessed without an exchange/context/registry, I also wanted to be able to load the properties in Java.
Both the functions throw the NullPointerException and I guess, it is because the code runs in Fuse.
public static Properties getProperties(String location) {
Properties prop = new Properties();
InputStream input = null;
try {
input = PropertyLoader.class.getClassLoader().getResourceAsStream(location);
prop.load(input);
} catch (IOException ex) {
log.error("Error loading properties file from: " + location, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
log.error(e);
}
}
}
return prop;
}
public static Properties getPropertiesFromFilesystem(String location) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(location);
prop.load(input);
} catch (IOException ex) {
log.error("Error loading properties file from: " + location, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
log.error(e);
}
}
}
return prop;
}
The Exception:
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Properties.java:434)[:1.8.0_91]
at java.util.Properties.load0(Properties.java:353)[:1.8.0_91]
at java.util.Properties.load(Properties.java:341)[:1.8.0_91]
at com.mycompany.util.PropertyLoader.getProperties(PropertyLoader.java:19)[319:camel-archetype-blueprint:0.0.14]
at com.mycompany.camel.blueprint.MyProcessor.process(MyProcessor.java:21)[319:camel-archetype-blueprint:0.0.14]
at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:63)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:192)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at java.util.TimerThread.mainLoop(Timer.java:555)[:1.8.0_91]
at java.util.TimerThread.run(Timer.java:505)[:1.8.0_91]
Any help would be highly appreciated.
Do not do that. You are looking for trouble.
Load properties the OSGi way (use .cfg as extension and a blueprint property-placeholder bean)
You have the added benefit of getting notified if the file changes (if you wish)
Inject them in a bean EVEN IF you are using only static methods.
Don't mix managed beans with unmanaged static code unless you know very well what you are doing.
If some "static" code requires properties means that it is stateful, and this class deserves to be instantiated to a bean.
Not sure why you are getting an NPE without a more complete example. If you need to use properties without a route, you should be using Camel's property placeholder facilities:
https://access.redhat.com/documentation/en-us/red_hat_jboss_fuse/6.3/html/apache_camel_development_guide/basicprinciples#BasicPrinciples-PropPlaceholders

How to set a default value to variables in Guice

Like we do the following in Spring
#Value("${varName:0}")
int varName;
Is there a way to do this using Google Guice?
In Guice you would annotate the method and make it optional. You then just assign the default value. If no property is there to be injected, it will be the default value.
For example:
public class TestModule3 extends AbstractModule {
#Override
protected void configure() {
// Properties p = new Properties();
// p.setProperty("myValue", "12");
// Names.bindProperties(binder(), p); // this binds the properties that usually come for a file
bind(Manager.class).to(ManagerImpl.class).in(Singleton.class);
}
public static interface Manager {
public void talk();
}
public static class ManagerImpl implements Manager {
#Inject(optional = true)
#Named("myValue")
int test = 0;
#Override
public void talk() {
System.out.println(test);
}
}
public static void main(String[] args) {
Manager instance = Guice.createInjector(new TestModule3()).getInstance(Manager.class);
instance.talk();
}
}
This will print "0" for you, because I commented out the property binding. If you remove the comments, it will bind the value 12 to the String myValue. The inject annotation takes care of the rest.
Hope that helps,
EDIT:
As #TavianBarnes pointed out, Guice 4+ has an OptionalBinder. I tried this for your usecase and could not make it work out of the box.
It appears that OptionalBinding is very useful for classes (actual instances), not for properties. Here is why:
You have to know all the properties in advance and bind them to their defaults. It is easy to forget them. The example shown by OP also shows that he does not know if he has the property available (based on the name).
Default implementation of property bindings don't work in combo with the OptionalBinding.
So the way you can make that work is like this:
OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("myValue"))).setDefault()
.toInstance("777");
Properties p = new Properties();
p.setProperty("myValue", "12");
// use enumeration to include the default properties
for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();) {
String propertyName = (String) e.nextElement();
String value = p.getProperty(propertyName);
OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named(propertyName))).setBinding()
.toInstance(value);
}
I had to copy the Named binding code and change it to support optional bindings.
In summary:
I would prefer to use the optional=true flag + default value in code for properties.
Use the OptionalBinding for actual classes that can be optional.
Finally, there is one more thing you could do - this is my solution in my code. I have a similar requirement (not the optional, but default values).
I want:
Bind my properties
Check if my properties are a variable
Replace the variable
If the variable is not available set a default
Apache offers a handy library for this already which I reuse. This is how my properties look like:
myProperty=${ENV_VAR_NAME:-600}
This is the default annotation of how to define a default value.
The above property says:
Use the evnironment variable "ENV_VAR_NAME".
If "ENV_VAR_NAME" is not set, use the value "600"
Then I bind it as follows:
InputStream resourceAsStream = getClass().getResourceAsStream(path);
if(resourceAsStream == null) {
throw new IllegalArgumentException("No property file found for path: " + path);
}
try {
p.load(resourceAsStream);
EnvironmentVariableSubstitutor envSubstitutor = new EnvironmentVariableSubstitutor(false);
Set<Object> keys = p.keySet();
for(Object k : keys) {
String property = p.getProperty(k.toString());
property = envSubstitutor.replace(property);
p.put(k, property);
}
} catch (IOException e) {
throw new IllegalStateException("Could not load properties", e);
} finally {
try {
resourceAsStream.close();
} catch (IOException e) {
log.error("Could not close stream for resource " + path);
}
}
Names.bindProperties(binder(), p);
What this code does is:
Load the properties from a resource file
Use the EnvironmentVariableSubstitutor to process the values of the properties and overwrite the result. (see loop)
finally, bind the modified properties to their names.
These are all the solutions I can come up with at short notice :) let me know if something's unclear
Edit 2:
there is some info on OptionalBindings and properties + how to handle default values in this google thread as well: https://groups.google.com/forum/#!topic/google-guice/7Ga79iU_sb0
Artur

Reading properties from an XML file using Input Stream?

Currently within my Java Application I have the following Class that I use in order to retrieve values from my properties file (application.properties):
public class MyProperties {
private static Properties defaultProps = new Properties();
static {
try {
java.io.InputStream in= MyProperties.class.getClassLoader().getResourceAsStream("application.properties");
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getProperty(String key) {
return defaultProps.getProperty(key);
}
}
An example of instantiating an int using the MyProperties class:
int maxNumberOfPeople = Integer.parseInt(MyProperties.getProperty("maximumPeople"));
I would like to change this class in order to read an XML properties file rather than e.g. application.Properties.
How can I do so, and still keep the ability to still instantiate values using the MyProperties class?
Read the javadoc for the Properties.loadFromXML(...) method.
Method summary:
Loads all of the properties represented by the XML document on the specified input stream into this properties table.
The Properties javadoc includes the DTD for the XML document (file).
It would be better to write your loader using a try-with-resources like this:
try (java.io.InputStream in = MyProperties.class.getClassLoader().
getResourceAsStream("application.properties")) {
// load properties
} catch (Exception e) {
e.printStackTrace();
}
Also, it is a bad idea to catch and squash exceptions like that.
Don't catch Exception.
If the properties failed to load, you most likely want the application to "bail out".
Finally, you probably shouldn't load the properties in a static initializer, because that leaves you with no clean way to deal with any exceptions that might arise.

How to instantiate an object using it's constructor outside a method java

I'd like to instantiate an object with it's constructor outside a method. Example:
public class Toplevel {
Configuration config = new Configuration("testconfig.properties");
public void method1() {
config.getValue();
...etc
}
}
If I do this right now...I get this error..
Default constructor cannot handle exception type IOException thrown by implicit super constructor. Must define an explicit constructor
I'd like to do something like this so I could call config anywhere in my class, right now I keep having to instantiate the Configuration objects...there's gotta be a way to do this...any help would be much appreciated, thanks in advance.
EDIT:
Configuration class:
public class Configuration {
private String mainSchemaFile;
public Configuration() {
}
public Configuration( String configPath ) throws IOException {
Properties prop = new Properties();
prop.load( new FileInputStream( configPath ));
this.mainSchemaFile= prop.getProperty("MAINSCHEMA_FILE");
}
Your Configuration constructor is declared to throw an IOException. Any code that instantiates a Configuration using this constructor must catch it. If you use a variable initializer, then you can't catch it, because you can't supply a catch block; there is no block you can put here, only an expression. There is no method to declare a throws clause on either.
Your alternatives:
Instantiate the Configuration in a Toplevel constructor. You can catch the exception in the constructor body, or you can declare that constructor that it throws the exception.
public class Toplevel {
Configuration config;
public Toplevel() {
try {
config = new Configuration("testconfig.properties");
} catch (IOException e) { // handle here }
}
// ...
Instantiate the Configuration in an instance initializer in the TopLevel class, where you can catch the exception and handle it.
public class Toplevel {
Configuration config;
{
try {
config = new Configuration("testconfig.properties");
} catch (IOException e) { // handle here }
}
// ...
Catch and handle the exception in the Configuration constructor, so calling code doesn't have to catch the exception. This isn't preferred, because you may have an invalid Configuration object instantiated. Calling code would still need to determine if it's valid.
public class Configuration {
// Your instance variables
private boolean isValid;
public Configuration( String configPath ) {
try {
// Your code that might throw an IOE
isValid = true;
} catch (IOException e) {
isValid = false;
}
}
When you create a new Toplevel object then you have not declared a specific constructor for it and the attribute of Toplevel is instantiated as your code describes it with Configuration config = new Configuration("testconfig.properties");
So you do not handle the IoException of the Configuration constructor!
A better way would be to declare a specific constructor of Toplevel like this:
public Toplevel(){
try{
this.config = new Configuration("testconfig.properties");
} catch (IOException e) {
// handle Exception
}
}

Categories

Resources