7

I am trying to read a property file from classpath using scala. But it looks like it won't work, it is different from java. The following 2 code snippet, one is java (working), another is scala (not working). I don't understand what is the difference.

// working
BufferedReader reader = new BufferedReader(new InputStreamReader(
Test.class.getResourceAsStream("conf/fp.properties")));

// not working 
val reader = new BufferedReader(new InputStreamReader(
getClass.getResourceAsStream("conf/fp.properties")));

Exception in thread "main" java.lang.NullPointerException
at java.io.Reader.<init>(Reader.java:78)
at java.io.InputStreamReader.<init>(InputStreamReader.java:72)
at com.ebay.searchscience.searchmetrics.fp.conf.FPConf$.main(FPConf.scala:31)
at com.ebay.searchscience.searchmetrics.fp.conf.FPConf.main(FPConf.scala)
zjffdu
  • 25,496
  • 45
  • 109
  • 159
  • Why don't you use [Config](https://github.com/typesafehub/config)? – Sergey Weiss Feb 27 '13 at 12:42
  • 3
    Got the solution, I should use absolute path here "/conf/fp.properties", but still not clear about why the relative path work in java but not in scala – zjffdu Feb 28 '13 at 02:23

6 Answers6

9

This code finally worked for me:

import java.util.Properties
import scala.io.Source

// ... somewhere inside module.

var properties : Properties = null

val url = getClass.getResource("/my.properties")
if (url != null) {
    val source = Source.fromURL(url)

    properties = new Properties()
    properties.load(source.bufferedReader())
}

And now you have plain old java.util.Properties to handle what my legacy code actually needed to receive.

Roman Nikitchenko
  • 12,800
  • 7
  • 74
  • 110
  • 1
    as in [link](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-) ** "The specified stream remains open after this method returns. " ** So you need to assign it a tmp var, then need to call close on that so the File descriptor is not leaked: `val reader = source.bufferedReader()` `properties.load(reader)` `reader.close()` – tam.teixeira Oct 29 '19 at 17:04
8

I am guessing that your BufferedReader is a java.io.BufferedReader

In that case you could simply do the following:

import scala.io.Source.fromUrl
val reader = fromURL(getClass.getResource("conf/fp.properties")).bufferedReader()

However, this leaves the question open as to what you are planning to do with the reader afterwards. scala.io.Source already has some useful methods that might make lots of your code superfluous .. see ScalaDoc

suls
  • 208
  • 1
  • 5
3

My prefered solution is with com.typesafe.scala-logging. I did put an application.conf file in main\resources folder, with content like:

services { mongo-db { retrieve = """http://xxxxxxxxxxxx""", base = """http://xxxxxx""" } }

and the to use it in a class, first load the config factory from typesafe and then just use it.

val conf = com.typesafe.config.ConfigFactory.load() conf.getString("services.mongo-db.base"))

Hope it helps!

Ps. I bet that every file on resources with .conf as extension will be read.

2

For reading a Properties file i'd recommend to use java.util.ResourceBundle.getBundle("conf/fp"), it makes life a little easier.

Chirlo
  • 5,989
  • 1
  • 29
  • 45
1

The NullPointerException you are seeing is caused by a bug in the underlying Java code. It could be caused by a mistyped file name.

Sometimes you get this error also if you're trying to load the resource with the wrong classloader.

  1. Check the resource url carefully against your classpath.
  2. Try Source.fromInputStream(getClass.getResourceAsStream(...))
  3. Try Source.fromInputStream(getClass.getClassLoader.getResourceAsStream())
  4. Maybe you are using other classloaders you can try?

The same story goes for Source.fromUrl(...)

If you're trying to load configuration files and you control their format, you should have a look at Typesafe's Config utility.

iwein
  • 25,788
  • 10
  • 70
  • 111
0

The Null Pointer Exception you are getting is from getResourceAsStream returning null. The following junit.scala snippet shows how there is a difference in class vs classloader. see What is the difference between Class.getResource() and ClassLoader.getResource()?. Here I assume fileName is the name of a file residing in the class path, but not a file next to the class running the test.

assertTrue(getClass.getClassLoader().getResourceAsStream(fileName) != null)
assertTrue(getClass.getClassLoader().getResourceAsStream("/" + fileName) == null)
assertTrue(getClass.getResourceAsStream(fileName) == null)
assertTrue(getClass.getResourceAsStream("/" + fileName) != null)
Community
  • 1
  • 1
harschware
  • 13,006
  • 17
  • 55
  • 87