I am quite familiar with Java and Maven, but not at all with Scala. I am trying to access Scala from Java and one of the problems I can't seem to understand is the following:
My Question
In AccessScala.java
I try to access a variable in WithinModule.scala
:
package me.parent.jModule;
public class AccessScala{
public static void main(String[] args){
WithinModule within = new WithinModule();
// -- this is like a static variable
System.out.println(WithinModule.string);
// -- this is like an instance variable
System.out.println(within.string);
// -- this is a getter, as it should be in Java
System.out.println(within.getString());
}
}
This variable should be public
package me.parent.jModule;
class WithinModule{
val string : String = "this is the local scala string";
}
But when running mvn clean package
it tells me this variable is private:
[ERROR] [Error] C:\projectLocation\parent\jModule\src\main\java\me\parent\jModule\AccessScala.java:7: string has private access in me.parent.jModule.WithinModule
[ERROR] [Error] C:\projectLocation\parent\jModule\src\main\java\me\parent\jModule\AccessScala.java:9: string has private access in me.parent.jModule.WithinModule
Basically, am I misunderstanding how this should work, or am I doing something wrong?
Project Setup
I put the project up on GitHub, with a summary of what may be relevant here. The files are organised like so
> parent
| > jModule
| | > src/main
| | | > java/me/parent/jModule
| | | | > AccessScala.java
| | | > scala/me/parent/jModule
| | | | > WithinModule.scala
| | > pom.xml
| > sModule
| | > src/scala/me/parent/sModule
| | | >ExternalModule.scala
| | > pom.xml
| > pom.xml
I took my parent pom.xml
mostly from here. With some modifications it ended up like below. This exact setup works fine on another project where there was (so far) only one case where Java was making use of a class written in Scala, but plenty of code in both languages. Testing and all worked fine, until we tried to access val
s from Scala within Java.
I use the Maven compiler, surefire and failsafe plugins to compile and test Java (no tests yet) and the Scala-Maven and ScalaTest plugins to compile and test Scala code (also no tests yet). They are configured to compile and test Scala first, then move on to Java.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.13</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- stuff for compiling and testing Java during `mvn package` -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<!-- This is for Scala compilation during `mvn package` -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.3.1</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<!--
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
-->
</executions>
</plugin>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<junitxml>.</junitxml>
<filereports>WDF TestSuite.txt</filereports>
</configuration>
<executions>
<execution>
<id>test</id>
<phase>process-test-resources</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<modules>
<module>jModule</module>
<module>sModule</module>
</modules>
</project>
PS
Any suggestions what is going on would be appreciated. As I mentioned I'm trying to make Java and Scala work together, which I hear should be quite easy, but I keep running into issues, this is one of them.
Analysing scalac -print
output we see that
class WithinModule {
val string : String = "this is the local scala string"
}
expands to something like
class iw$WithinModule extends Object {
private[this] val string: String = _;
<stable> <accessor> def string(): String = iw$WithinModule.this.string;
def <init>(): $line184.iw$WithinModule = {
iw$WithinModule.super.<init>();
iw$WithinModule.this.string = "this is the local scala string";
()
}
}
where we note def string(): String
, therefore in AccessScala.java
try
WithinModule within = new WithinModule();
System.out.println(within.string());