How to reference java.sql from a Scala Script without encountering SecurityException?
Clash Royale CLAN TAG#URR8PPP
How to reference java.sql from a Scala Script without encountering SecurityException?
Since Java 9, calling objects defined in java.sql from within Scala throw a java.lang.SecurityException when used directly from a scala script.
Java Version: 10.0.1
Scala Version: 2.12.4
sbt Version: 1.2.0
The below screenshot is an entire minimum working example, with console output for a working and non-working version. Specifically: copying the script code into a class, and running it from that class, resolves the issue. Is there a way to write a Scala script that directly uses objects from java.sql
?
java.sql
build.sbt
build.sbt
name := "mypackage"
version := "0.1"
scalaVersion := "2.12.4"
libraryDependencies += "org.postgresql" % "postgresql" % "42.2.4"
broken-script.scala
broken-script.scala
import java.sql.Connection, DriverManager
import java.util.Properties
object Main
private def url = "jdbc:postgresql://localhost:5432/postgres"
val credentials: Properties =
val properties = new Properties()
properties.setProperty("user", "integration_test")
properties.setProperty("password", "integration-pass")
properties
def connect(): Connection =
DriverManager.getConnection(url, credentials)
def run(): Unit =
connect()
Main.run()
As shown in the console output below, broken-script.scala
encounters a SecurityException.
broken-script.scala
brokenScript.scala Output
brokenScript.scala Output
:load scripts/broken-script.scala
Loading scripts/broken-script.scala...
import java.sql.Connection, DriverManager
import java.util.Properties
defined object Main
java.lang.securityException: Prohibited package name: java.sql
at java.base/java/lang.ClassLoader.preDefineClass(ClassLoader.java:891)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java 1007)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:545)
at java.base/java.net.URLClassLoader.access$100(URLClassLoader.java:83)
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:453)
at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:447)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/net.URLClassLoader.findClass(URLClassLoader.java:446)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:566)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:553)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
at Main$.connect(scripts/broken-script.scala:26)
at Main$.run(scripts/broken-script.scala:30)
src/main/scala/mypackage/Main.scala
src/main/scala/mypackage/Main.scala
package mypackage
import java.sql.Connection, DriverManager
import java.util.Properties
object Main
private def url = "jdbc:postgresql://localhost:5432/postgres"
val credentials: Properties =
val properties = new Properties()
properties.setProperty("user", "integration_test")
properties.setProperty("password", "integration-pass")
properties
def connect(): Connection =
DriverManager.getConnection(url, credentials)
def run(): Unit =
connect()
working-script.scala
working-script.scala
mypackage.Main.run()
println("Success")
An image of the entire project.
@Rich Java 10. Switched to Java 8 and it works perfectly.
– Will Beason
Aug 16 at 13:24
3 Answers
3
This situation with SecurityException
looks very weird. I tried to reproduce your issue on my machine, but I didn't face SecurityException
despite I followed the described steps.
SecurityException
SecurityException
I used the next code:
import java.sql.DriverManager
import java.util.Properties
object PostgresTest extends App
def connect() =
val properties = new Properties()
properties.setProperty("user", "postgres")
properties.setProperty("password", "admin")
println("Attempt to establish connection ...")
val someMetaData = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", properties)
.getMetaData
.getDefaultTransactionIsolation
println(s"If you see this line, it works fine: $someMetaData")
I tried the different approaches:
with sbt console
::load /home/username/space/test-project/src/main/scala/PostgresTest.scala
and PostgresTest.connect()
- no SecurityException
sbt console
:load /home/username/space/test-project/src/main/scala/PostgresTest.scala
PostgresTest.connect()
SecurityException
sbt console
and :paste
mode, it works fine
sbt console
:paste
sbt runMain
connect()
IntelliJ
SBT - 1.1.1
and Scala - 2.12.4
SBT - 1.1.1
Scala - 2.12.4
I suggest that can be a problem on IntelliJ side. If any of the scenarios which I described above wouldn't work for you, please, notify me.
For Java 10: (1) :load fails, (2) :paste fails, (3) runMain fails. I'm not sure what (4) is. For Java 8, they all pass.
– Will Beason
Aug 16 at 13:47
As Rich pointed out in the comments, the problem is using Java 9 or later because they changed how classloaders work. The non-ideal fix is to downgrade to Java 8.
To ensure Java 8 is installed (Linux):
sudo update-alternatives --display java
To default to Java 8:
sudo update-alternatives --config java
After switching to Java 8, everything works fine. The solution is not ideal because it relies on using a version of Java that won't be supported for much longer.
Pleased you found something that works, even if it's non-ideal. I might've thought sbt would be able to handle this somehow, so have added sbt tag.
– theStrawMan
Aug 16 at 23:05
It does sound like an
sbt
bug. Hopefully someone will post a proper fix here and win some magic internet points.– Rich
Aug 17 at 14:35
sbt
Edit: See later comment on class-loaders.
I haven't ever had to reference java.sql myself so this is not from personal experience, but it looks like the same problem as in this question: java.lang.SecurityException: error when executing outside Eclipse, where the problem occurs only outside the IDE. Doesn't look like you have your own class or package starting with 'java', so it's not that. What do your classpaths look like? It is a problem with the way the IDE builds with dependencies, so I think will require action within Intellij rather than changing the script - something like this: How to build JARs from Intellij properly.
I'm actually building the JARs with sbt. The Intellij is just for showing the structure. I got the same behavior in an otherwise clean directory. Though for the script, all of the jars should just be downloaded as dependencies, right?
– Will Beason
Aug 14 at 16:30
Ok, are you using an old version of sbt? It looks like some class-loader things changed when Java 9 was introduced.
– theStrawMan
Aug 14 at 23:39
I'm using sbt 1.2.0, the latest stable version.
– Will Beason
Aug 15 at 15:34
Ok, so not sbt. In response to your question "Though for the script, all of the jars should just be downloaded as dependencies, right?", possibly. That would be done like this. I would hope you wouldn't need that for something in the JDK itself, but possibly that's the only approach. Unfortunately I'm not sure there.
– theStrawMan
Aug 16 at 0:18
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Are you using Java 9? See stackoverflow.com/questions/46494112/…
– Rich
Aug 16 at 9:25