I have a maven project with the file src/main/resources/barcoding.properties. I keep getting a null pointer with the code below when trying to get the barcoding.properties file with the code below:
public class BarcodingProperties{
private static Properties props = null;
private static void getProperties() {
System.out.println("we in getProperties");
props = new Properties();
InputStream in = BarcodingProperties.class.getClass().getClassLoader().getResourceAsStream("barcoding.properties"); <-- This line returns null pointer exception.
System.out.println("in. = "+in.toString());
try {
props.load(in);
} catch (IOException e) {
System.out.println("unable to load properties");
e.printStackTrace();
}
}
}
When i build the project and look into the jar file, barcoding.properties exists right in the project root.
Why does this return null and how can i fix it?
You are trying to use the classloader of Class for loading the resource, instead of BarcodingProperties like this:
BarcodingProperties.class.getClassLoader().getResourceAsStream("barcoding.properties");
The Class's classloader is null, indicating that it was loaded by the bootstrap class loader, see Stock JDK classes and the "null" ClassLoader? for more information.
This seems strange:
BarcodingProperties.class.getClass()
BarcodingProperties.class is the BarcodingProperties class object instance. if you do a getClass() on that, it'll return the Class class object...
Ideone fiddle though with String.class
What you want is probably:
InputStream in = BarcodingProperties.class.getClassLoader().getResourceAsStream("barcoding.properties");
Related
When I start the application, I need to load properties from different sources: war, file system, database, and JVM. I need to load properties once and use them within running my application. I do not need to refresh it. I don't have DI - it is a simple java application with singletons. I decide to create AppProperties singleton and load properties when starting the application. It is the best solution by the current time for me(I hope somebody makes the best solution). It is my Singleton:
import java.io.InputStream;
import java.util.Properties;
public class AppProperties {
private static AppProperties instance;
private Properties propertiesFromWar;
private Properties propertiesFromFile;
private Properties propertiesFromDB;
private AppProperties() {
propertiesFromWar = new Properties();
try {
propertiesFromWar.load(getPropertiesAsInputStreamFromWar());
propertiesFromFile.load(getPropertiesAsInputStreamFromFile());
propertiesFromDB.load(getPropertiesAsInputStreamFromDB());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private InputStream getPropertiesAsInputStreamFromDB() {
//some implementation
return null;
}
private InputStream getPropertiesAsInputStreamFromFile() {
//some implementation
return null;
}
private InputStream getPropertiesAsInputStreamFromWar() {
return getClass().getResourceAsStream("META-INF/application.properties");
}
public static AppProperties getInstance() {
if (instance == null) {
instance = new AppProperties();
}
return instance;
}
public String getProperty(String key) {
String value;
value = System.getProperty(key);
if (value == null) {
value = propertiesFromDB.getProperty(key);
if (value == null) {
value = propertiesFromFile.getProperty(key);
if (value == null) {
value = propertiesFromWar.getProperty(key);
}
}
}
return value;
}
}
But I do not understand, How can I use it in tests. Because I hardcode paths for aplication.properties files. And when I will create this instance in the tests, I will create AppProperties with real properties.
I tried to add a public method like load(filePath). But with this method, it will be not a singleton. If somebody will call this method in another place of application - my singleton will be reloaded with new data. Now I have 2 problems.
If I add load() method - it will be dangerous for reloading data. But I can use it in tests.
If I do not add this method - I can not test it.
P.S I read this article The Little Singleton
But I do not understand some moments. If I have singleton with private constructor, I can not extend it like in article.
In your test resources directory, create META-INF directory. Here create a file application.properties and add some properties for testing purposes in it.
Make sure the above directory is in the classpath when you will run the tests. This way, when getPropertiesAsInputStreamFromWar() is called, it will look for META-INF/application.properties in the classpath.
Being tests allow specifying JVM launch arguments, this can be "solved" pretty easily.
This also adds some flexibility.
java -DpropertiesPath="..." -jar yourJar.jar
And, adapting your code
private InputStream getPropertiesAsInputStreamFromWar() {
final String propertiesPath = Objects.requireNonNull(System.getProperty("propertiesPath"));
return getClass().getResourceAsStream(propertiesPath);
}
Instead of requireNonNull, you could use a default value, e.g.
META-INF/application.properties.
Changing path to hardcoded string - works, however this is not an option.
Test fails because it cannot find the resource, even though it's there.
Cities.java
/*
This Singleton Class loads cities.json into an ArrayList and by using a boolean method isCity can tell if passed
String is city or not.
*/
public class Cities
{
private static Cities single_instance = null;
ArrayList<City> cityArrayList;
private Cities() throws IOException
{
String path = new ClassPathResource("cities.json").getFile().getAbsolutePath();
Gson gson = new Gson();
Type cityListType = new TypeToken<ArrayList<City>>()
{
}.getType();
cityArrayList = gson.fromJson(new FileReader(path), cityListType);
}
public static Cities getInstance() throws IOException
{
if (single_instance == null)
single_instance = new Cities();
return single_instance;
}
public boolean isCity(String cityToLookFor)
{
for (City city : cityArrayList)
{
if (city.getName().strip().equalsIgnoreCase(cityToLookFor))
{
return true;
}
}
return false;
}
}
CitiesTest.java
class CitiesTest
{
Cities cities = Cities.getInstance();
CitiesTest() throws IOException {}
#Test
void isCityTest2()
{
assertFalse(cities.isCity("USA"), "City not found in localDbase");
}
#Test
void isCityTest3()
{
assertEquals(true, cities.isCity("Paris"), "City not found in localDbase");
}
}
pom.xml
https://pastebin.com/fMQNknM1
java.io.FileNotFoundException: class path resource [cities.json] cannot be resolved to URL because it does not exist
at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:150)
at gr.serresparc.palantir.repository.Cities.<init>(Cities.java:24)
at gr.serresparc.palantir.repository.Cities.getInstance(Cities.java:35)
at gr.serresparc.palantir.repository.CitiesTest.<init>(CitiesTest.java:12)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at
Remove the <targetPath>..</targetPath> from the resources section of the pom.xml. You might as well remove the whole resources section.
The executed test code is not looking for the file in within src/main/resources but within target/classes. The classpath resource cities.json needs to appear there.
Please be also aware that if the application is shipped as a spring boot jar file then it is not possible to read a classpath resource as file.
Try to change the code as below,
String path = new ClassPathResource("classpath:cities.json").getFile().getAbsolutePath();
Please, note I have added classpath: in front of cities.json.
EDIT
You can also get the InputStreamReader like below, First, inject ResourceLoader.
#Autowired
ResourceLoader resourceLoader;
Then load json file just like below:
cityArrayList = gson.fromJson(new JsonReader(resourceLoader.getResource("classpath:cities.json").getInputStream()), cityListType);
i am trying to verify that given path is a directory or file in HDFS but it results NPE at fs.getFileStatus(path).isDir() line. i don't understand what's the issue here , even i verified the path that's not null.
public static class RegexExcludePathFilter extends Configured implements
PathFilter {
private String path;
String patterns = "hdfs://localhost:9100/user/input-new/ncdc/filterdata/2007.[0-1]?[0-2].[0-9][0-9].txt" ;
Configuration conf;
Pattern pattern;
FileSystem fs;
#Override
public boolean accept(Path path) {
System.out.println(path);
try {
if(fs.getFileStatus(path).isDir()){
System.out.println(path);
return true;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return path.toString().matches(patterns);
}
}
line 108 points to if statement in accept method.
thanks in advance
Have you inisialiezed FileSystem fs? I think that's the one that is null
make a constructor
public FileSystem(){
fs = new FileSystem();
}
Edit: i just noticed you are using a static class so i dont know if making a constructor will work.
Well you've already established that path is not null. The only thing that can be null now, is the FileStatus object returned. Check if that is null.
When chaining methods together like this, you should always be sure that somewhere in the middle a method cannot return null. If that may happen, you should never chain. Basically the method that can return null, breaks the chain.
How to load a properties file in java without calling laod method separately
i want to load the file while instantiation of the properties object itself.
like i have pasted below but i am not able to succeed in it.
class test{
Properties configFile = new Properties(load(new FileInputStream("config.properties"));
}
Just create a separate method to do that - potentially in a helper class you can use elsewhere:
public class PropertiesHelper {
public static Properties loadFromFile(String file) throws IOException {
Properties properties = new Properties();
FileInputStream stream = new FileInputStream(file);
try {
properties.load(stream);
} finally {
stream.close();
}
return properties;
}
}
Note that due to the possibility of an IOException, you'll still need to be careful where you call this from. If you want to use it in an instance initializer, you'll need to declare that all of your constructors can throw IOException.
Something along the lines of this:
class Test {
Properties configFile = new Properties() {{ load(new FileInputStream("config.properties")); }};
}
You are actually sub classing Properties here and using its initialization section.
load(..) might throw an Exception if so you would need to add a try { ... } catch () {}
My objective is to have a private static Properties object in my class, to act as defaults when creating other Properties objects needed by my application. The current implementation looks like this:
public class MyClass {
private static Properties DEFAULT_PROPERTIES = new Properties();
static {
try {
DEFAULT_PROPERTIES.load(
MyClass.class.getResourceAsStream("myclass.properties"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Looking at it, it works, but it doesn't feel right.
How would you do it?
There are basically two ways. First way is using the static block as you have shown (but then with an ExceptionInInitializerError instead of the RuntimeException). Second way is using a static method which you call immediately on declaration:
private static Properties DEFAULT_PROPERTIES = getDefaultProperties();
private static Properties getDefaultProperties() {
Properties properties = new Properties();
try {
properties.load(MyClass.class.getResourceAsStream("myclass.properties"));
} catch (IOException e) {
throw new ConfigurationException("Cannot load properties file", e);
}
return properties;
}
The ConfigurationException can just be your custom class extending RuntimeException.
I personally prefer the static block because it doesn't make sense having a method which is executed only once ever in its life. But if you refactor the method so that it takes a filename and can be reused globally, then that would be more preferred.
private static Properties DEFAULT_PROPERTIES = SomeUtil.getProperties("myclass.properties");
// Put this in a SomeUtil class.
public static Properties getProperties(String filename) {
Properties properties = new Properties();
try {
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(filename));
} catch (IOException e) {
throw new ConfigurationException("Cannot load " + filename, e);
}
return properties;
}
Instead of a generic RuntimeException, I would throw an ExceptionInInitializerError, which is ment for exacctly this purpose. From the API documentation: "Signals that an unexpected exception has occurred in a static initializer."
Seems acceptable to me; load in the static initialiser, it gets called only when the class is referenced, and is only called once. I like it. The only thing I'd do is make it final.
Well, aside from the exception. I'd try and avoid that somehow (I have in the back of my mind that you should avoid exceptions in those types of initialisers, but I could be wrong on that).