Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

build.sbt

name := "mypackage"
version := "0.1"
scalaVersion := "2.12.4"

libraryDependencies += "org.postgresql" % "postgresql" % "42.2.4"

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.

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

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

mypackage.Main.run()

println("Success")

An image of the entire project.

enter image description here

like image 229
Will Beason Avatar asked Aug 10 '18 16:08

Will Beason


2 Answers

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.

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 and :paste mode, it works fine

  • sbt runMain with code above + call of connect()method - works fine
  • via IntelliJ wizard for scripts and the main method - both of them work fine.

SBT - 1.1.1 and 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.

like image 89
Artem Avatar answered Oct 11 '22 00:10

Artem


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.

like image 29
Will Beason Avatar answered Oct 11 '22 00:10

Will Beason