13

I was trying to pull environment variables into a scala script using java Iterators and / or Enumerations and realised that Dr Frankenstein might claim parentage, so I hacked the following from the ugly tree instead:

import java.util.Map.Entry
import System._

val propSet = getProperties().entrySet().toArray()
val props   = (0 until propSet.size).foldLeft(Map[String, String]()){(m, i) =>
  val e = propSet(i).asInstanceOf[Entry[String, String]]
  m + (e.getKey() -> e.getValue())
}

For example to print the said same environment

props.keySet.toList.sortWith(_ < _).foreach{k =>
  println(k+(" " * (30 - k.length))+" = "+props(k))
}

Please, please don't set about polishing this t$#d, just show me the scala gem that I'm convinced exists for this situation (i.e java Properties --> scala.Map), thanks in advance ;@)

Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
Don Mackenzie
  • 7,953
  • 7
  • 31
  • 32

6 Answers6

8

Scala 2.10.3

import scala.collection.JavaConverters._

//Create a variable to store the properties in
val props = new Properties

//Open a file stream to read the file
val fileStream = new FileInputStream(new File(fileName))
props.load(fileStream)
fileStream.close()

//Print the contents of the properties file as a map
println(props.asScala.toMap)
jencoston
  • 1,262
  • 7
  • 19
  • 35
Sarath
  • 1,438
  • 4
  • 24
  • 40
  • Hi Sarath. Thanks for contributing to the site. We prefer answers on StackOverflow to have a bit more explanation than just posting code. Try reading this [guide to posting good answers](http://stackoverflow.com/help/how-to-answer) for more help :) – starsplusplus Feb 25 '14 at 14:58
7

Scala 2.7:

val props = Map() ++ scala.collection.jcl.Conversions.convertMap(System.getProperties).elements

Though that needs some typecasting. Let me work on it a bit more.

val props = Map() ++ scala.collection.jcl.Conversions.convertMap(System.getProperties).elements.asInstanceOf[Iterator[(String, String)]]

Ok, that was easy. Let me work on 2.8 now...

import scala.collection.JavaConversions.asMap
val props = System.getProperties() : scala.collection.mutable.Map[AnyRef, AnyRef] // or
val props = System.getProperties().asInstanceOf[java.util.Map[String, String]] : scala.collection.mutable.Map[String, String] // way too many repetitions of types
val props = asMap(System.getProperties().asInstanceOf[java.util.Map[String, String]])

The verbosity, of course, can be decreased with a couple of imports. First of all, note that Map will be a mutable map on 2.8. On the bright side, if you convert back the map, you'll get the original object.

Now, I have no clue why Properties implements Map<Object, Object>, given that the javadocs clearly state that key and value are String, but there you go. Having to typecast this makes the implicit option much less attractive. This being the case, the alternative is the most concise of them.

EDIT

Scala 2.8 just acquired an implicit conversion from Properties to mutable.Map[String,String], which makes most of that code moot.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • As a side note, this is the first time I do Java <-> Scala collection conversions. The last time I tried I wasn't experienced enough to get it to work. And not only did I get the chance to overcome my previous defeat, but I find this particular problem of much interest, as I find myself now and then perusing the system properties! – Daniel C. Sobral Jan 06 '10 at 22:01
  • Thanks Daniel, I'll give your answer a proper look later. I'm pleased to have provoked your interest in this topic. – Don Mackenzie Jan 06 '10 at 22:57
  • @Daniel, I suspect that this is the gem I was looking for, just a shame about the cast, especially as Properties should implement Map[String, String]. These conversions are a great find for me. – Don Mackenzie Jan 07 '10 at 00:13
  • Just to make clear, the cast is Java's implementation of Properties' fault, not Scala's. – Daniel C. Sobral Jan 07 '10 at 12:34
  • Daniel, the Chaotic Good Elf Mage defeats the old, gnarly, villainous beast which is the Java Properties construct. Sorry, but your first comment reminded me of an RPG... – Travis Schneeberger Jan 07 '10 at 22:19
  • No problem, but I'm more of a lawful good dwarf fighter, even if I do look like an elf. :-) – Daniel C. Sobral Jan 07 '10 at 22:50
  • This answer is outdated (as it goes with Scala unfortunately) – iwein Jan 19 '12 at 19:16
7

In Scala 2.9.1 this is solved by implicit conversions inside collection.JavaConversions._ . The other answers use deprecated functions. The details are documented here. This is a relevant snippet out of that page:

scala> import collection.JavaConversions._  
import collection.JavaConversions._

scala> import collection.mutable._
import collection.mutable._
scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3)
jul: java.util.List[Int] = [1, 2, 3]
scala> val buf: Seq[Int] = jul
buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2)
m: java.util.Map[String,Int] = {hello=2, abc=1} 

Getting from a mutable map to an immutable map is a matter of calling toMap on it.

iwein
  • 25,788
  • 10
  • 70
  • 111
  • Thanks for the update, Daniel did provide an edit to his answer mentioning these implicits. Ironically enough accessing the environment is going to be even more straightforward in scala 2.10, just use the immutable map returned by the sys.env method. – Don Mackenzie Jan 21 '12 at 12:06
  • 2
    Just realised that it was a conversion for properties to a Scala Map I'd asked for, however Scala 2.10 also has a sys.props method to access the system properties as well. – Don Mackenzie Jan 21 '12 at 12:18
  • 1
    The edit in Daniels answer is about Scala 2.8, and it has changed again in 2.9... I know it's confusing. – iwein Apr 28 '12 at 11:05
4

In Scala 2.8.1 you can do it with asScalaMap(m : java.util.Map[A, B]) in a more concise way:

var props = asScalaMap(System.getProperties())

props.keySet.toList.sortWith(_ < _).foreach { k =>
  println(k + (" " * (30 - k.length)) + " = " + props(k))
}
Vitalii Fedorenko
  • 110,878
  • 29
  • 149
  • 111
  • Thanks Vitalii, I took a look at asScalaMap and there's also version of asScalaMap which allows an implicit conversion from a java Properties instance to a Scala mutable Map[String, String]. – Don Mackenzie Feb 05 '11 at 13:03
2

In Scala 2.13.2:

import scala.jdk.javaapi.CollectionConverters._

val props = asScala(System.getProperties)
Ava
  • 818
  • 10
  • 18
1

Looks like in the most recent version of Scala (2.10.2 as of the time of this answer), the preferred way to do this is using the explicit .asScala from scala.collection.JavaConverters:

import scala.collection.JavaConverters._

val props = System.getProperties().asScala

assert(props.isInstanceOf[Map[String, String]])
Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111