JDK compiler fails for "open" module - java

Using current JDK build 9-ea+143's javax.tools.JavaCompiler tool, I can compile the simple (empty) example module without an error:
module com.foo.bar { }
If I add open as in:
open module com.foo.bar { }
...the compiler error reads:
/module-info.java:1: error: class, interface, or enum expected
open module com.foo.bar {
^
Syntax based on http://cr.openjdk.java.net/~mr/jigsaw/spec/lang-vm.html
Is the current JDK 9 build not up-to-date with this spec or am I missing an option to be passed to JavaCompiler?

To get the newest Jigsaw features, you need to use the Jigsaw EA build (as opposed to the regular EA builds). I created a GitHub repo exploring open packages and modules (to make reflection work) and also wrote about it - it definitely works on b146.

Related

Intellij can't find java.net.http when compiling with Java 11

I'm trying to get one of my projects ready for Java 11 but for some reason Intellij can't find java.net.http. It isn't underlining it as not found in module-info.java like it would if I typed it wrong but when I try build the project I get the error below. I've tried reinstalling Intellij 2018.2.3 and uninstalling all other versions of Java. Any advice on how to get this working would be appreciated.
Error:
Information:java: Errors occurred while compiling module 'crawler'
Information:javac 11 was used to compile java sources
Information:15/09/2018 11:16 - Compilation completed with 1 error and 0 warnings in 636 ms
C:\Users\Will\IdeaProjects\crawler\src\module-info.java
Error:(2, 22) java: module not found: java.net.http
module-info.java:
module crawler {
requires java.net.http;
}
Request.java:
package Request;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Request {
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("starting download");
String body = HttpClient.newBuilder().build().send(HttpRequest.newBuilder().uri(URI.create("https://example.com")).build(), HttpResponse.BodyHandlers.ofString()).body();
System.out.println("finished download:" + body);
}
}
Structure:
crawler
src
Request
Request.java
module-info.java
In the case that the above proposed resolution (by #Will) does not solve your issue as was the case with me (i.e. setting the project language level), check to to see what the bytecode target version of your java compiler has been set to, in your project preferences:
I had the wrong project language level set. To use java.net.http you need it to be at least 11. To change the project language level see: https://www.jetbrains.com/help/idea/project-page.html
Hopefully this helps someone else out.
I had the same problem with the package jdk.jfr.
This is how I fixed it. It should work for you too.
In order to make it work I had to make 2 changes:
First I had to set the language level to 11; see in the picture below.
Then I had to adjust the Java Compiler. The Target bytecode version is 11 and I set the project bytecode version Same as language level. Then you don't have to change all of them constantly. Please see picture below.
For those who are having this problem in 2022, even if the solutions mentioned here did not help, I was able to figure out what the problem was and how to fix this.
First of all I wanted to make sure that the problem is not from my Maven config, so I ran the following in my terminal:
mvn package
followed by:
java -cp target/covid-cases-cli-1.0-SNAPSHOT.jar org.matrixeternal.covidcasescli.App
and it was build without any errors whatsoever. So it means something is up with IntelliJ.
I am using Java 17 and building with Maven using IntelliJ. IntelliJ uses its own internal command to build the project. To override this behaviour, you must go to Preferences - Build, Execution & Deployment - Build Tools - Maven - Runner and select the option Delegate IDE build/run actions to maven which will essentially run directly from the Maven config file using the mvn tool installed in the system, instead of using the IDE command.
Set the compiler for IntelliJ as Java 11
IntelliJ Idea-> Preferences-> Build, Execution, Deployment -> Java Compiler
Select java 11 from the drop down

How to suppress the "requires transitive directive for an automatic module" warning properly?

After upgrading a Maven project to Java 9 and adding a module descriptor, javac complains about a transitive dependency for an automatic module:
[WARNING] /.../src/main/java/module-info.java:[3,35] requires transitive directive for an automatic module
An example module-info.java to reproduce the problem:
module com.example.mymodule {
exports com.example.mymodule.myexportedpackage;
requires transitive com.google.common;
}
The meaning of this warning is completely clear, here are some related links:
What's the difference between requires and requires transitive statements in Java 9?
Why does javac complain about named automatic-modules?
Related OpenJDK issue
The question is — how to suppress this warning, without fixing the actual issue, and without disabling all the other javac warnings?
I've tried the following options, but none of them worked:
#SuppressWarnings("module") in module-info.java
#SuppressWarnings("all") in module-info.java
-Xlint:all,-module command line option
Unfortunately, I cannot fix the actual issue (for now) because "my" module has return types and annotations from third-party (automatic) modules (e.g. Guava). Thus, if I'd use "requires com.google.common" (without transitive), then there would be a different warning, e.g.:
[WARNING] .../MyClass.java:[25,20] class com.google.common.collect.Table in module com.google.common is not indirectly exported using requires transitive
And of course I cannot define module descriptors for the third-party libraries (which are automatic modules right now).
I'm using -Werror which I'd prefer to keep, so the warning isn't merely annoying...
P.S. I do not intend to publish my artifacts to any public repositories.
You could try out the option of switching off the warning using
-Xlint:-requires-transitive-automatic
The changes for which were merged with JDK-8178011 stating:-
There should be two new warnings:
when a named module "requires transitive" an automatic module (default on)
when a named module "requires" an automatic module (default off)
Inferring this from the changes made here and also from the edit to the JEP 261: Module System which confirms that(emphasis mine):-
In both of the modular modes the compiler will, by default, generate
various warnings related to the module system; these may be disabled
via the option -Xlint:-module.
More precise control of these warnings
is available via the exports, opens, requires-automatic, and
requires-transitive-automatic keys for the -Xlint option.
You can also just use #SuppressWarnings like so:
#SuppressWarnings({ "requires-automatic", "requires-transitive-automatic" })
module foo {
// ...
}
The JDK itself uses this technique.
Sadly, the accepted answer didn't help me.
BTW, I am using Java 14 with a bunch of module system hacks for JUnit.
I had to add another flag, so the complete list looks as following:
-Xlint:-exports -Xlint:-requires-transitive-automatic -Xlint:-requires-automatic
I have searched for the error message and found the source code. There, one can see that the corresponding compiler key is called compiler.warn.leaks.not.accessible.not.required.transitive, with the command line arg -Xlint:exports.

What is the right way to expose a private Java9 module's package to JUnit?

I have an "executable" Java 9 module (meaning it won't expose any packages, it just contains a main function) which I need to test.
I am using Gradle's java-library and org.gradle.java.experimental-jigsaw plugins.
I have some package-private methods I need to test, and when I run in IntelliJ the tests work, but when running with Gradle, I get many errors like this:
abc.MyClassTest > myTestMethod FAILED
java.lang.IllegalAccessException
In the Gradle report, I see the root of the error:
class org.junit.runners.BlockJUnit4ClassRunner (in module junit)
cannot access class abc.MyClassTest (in module com.my.mod)
because module com.my.mod does not export abc to module junit
If I add this to my module-info.java file, it works with a warning:
exports abc to junit; // I don't really want to export this
Warning (when compiling):
warning: [module] module not found: junit
This looks pretty horrible even without the warning, in my opinion.
My question: how to "open" this package for tests only to avoid warnings and errors?
As the Gradle Plugin is still experimental (6 months after the release of Java 9), it seems it still has some bugs and missing features.
But here's how to work around the issue while the Gradle devs don't improve the situation.
Add this to your build file:
test {
doFirst {
jvmArgs += [
'--add-exports', "module/package=junit",
]
}
}
Where module/package is the name of the module and package you need to make visible to JUnit.
This is basically equivalent to the exports package to junit clause in module-info.java, but without having the clause make into the compiled jar!
This option is not documented in javac -help, but you can at least find it mentioned in the Oracle JDK Docs and, more thoroughly, in JEP-261... see the Breaking encapsulation section.

Do Kotlin 1.2.10 and Java 9 have opposite rules regarding automatic modules?

I have a Gradle project using the Kotlin Gradle plugin. I want to build a Java 9 module, so my directory structure looks like this:
src/main/java/
- module-info.java
src/main/kotlin/
- Foo.kt
- Bar.kt
build.gradle
...
My build.gradle declares the following dependencies:
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.10"
compile "org.jetbrains.kotlin:kotlin-reflect:1.2.10"
compile "org.junit.jupiter:junit-jupiter-api:5.0.2"
}
and I use all of these dependencies in my Kotlin source (Foo.kt, Bar.kt, ...).
Everything works hunky-dory if I write my module-info.java like so:
module my.module {
requires kotlin.stdlib;
exports my.module.pkg;
}
and if I supply all my compile-time dependencies to javac during the compileJava task using this technique.
However if I turn on -Xlint:all for the Java compiler during the compileJava task (to compile module-info.java), I get the following warnings:
/path/to/my.module/src/main/java/module-info.java:26: warning: requires directive for an automatic module
requires kotlin.stdlib;
^
So here we have the Java compiler, javac complaining that kotlin.stdlib is an automatic module so I shouldn't have a requires clause for it.
But if I delete the requires clause to make javac happy, it makes kotlinc even angrier than javac was (I get an error not a warning):
e: /path/to/my.module/src/main/java/module-info.java: The Kotlin standard library is not found in the module graph. Please ensure you have the 'requires kotlin.stdlib' clause in your module definition
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':my.module:compileKotlin'.
Now I can fix that, too, by editing my compileKotlin task thus:
compileKotlin {
doFirst {
kotlinOptions.freeCompilerArgs = ['-Xallow-kotlin-package']
}
}
But this only leads to MORE errors during the compileKotlin task, all looking like this one:
e: /path/to/my.module/src/main/kotlin/Foo.kt: (27, 30): Symbol is declared in module 'org.junit.jupiter.api' which current module does not depend on
And then if I try to force compileKotlin to take a module path rather than a classpath by adding "-Xmodule-path=${classpath.asPath}" to freeCompilerArgs and setting classpath to be empty, the Kotlin compiler can't find anything at all, and I end up with zillions of unresolved reference errors!
Why is the Kotlin compiler telling me I have to have requires kotlin.stdlib; when the Java compiler says the opposite? How can I get Kotlin and Java to work together to produce a Java 9 module?
If you're authoring Java 9 module in Kotlin, you have to declare requires kotlin.stdlib in your module-info.java in order to satisfy runtime dependencies of the compiled Kotlin code in addition to the explicit dependencies on the standard library API.
javac warns you about requiring an automatic module when lint is enabled, because automatic modules have some potential drawbacks compared to normal modules. Until the standard library is compiled as a normal module, you have to deal with this warning.
-Xallow-kotlin-package compiler flag allows you to omit require kotlin.stdlib, because it is intended to be used only when the standard library itself is compiled. Obviously, if you specify this flag and omit that requirement, you won't be able to use any API from the standard library, so this is not really an option for you.
I find it easiest to simply suppress the warnings for use of an automatic module. (In my case I have to use some automatic modules whether I want to or not, so these warnings are just distracting noise.) I have the following in my build.gradle.kts:
val compilerArgs = listOf(
"-Xlint:all", // Enable all warnings except...
"-Xlint:-requires-automatic", // Suppress "requires directive for an automatic module" warnings from module-info.java
"-Xlint:-requires-transitive-automatic" // Suppress "requires transitive directive for an automatic module" warnings from module-info.java
)
// This task will compile all Java code in the target module except for test code.
tasks.compileJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}
// This task will compile all Java test code in the target module.
tasks.compileTestJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}

How do I import 3rd party jars with Buildr?

I am working on my first Java app. A co-worker started it but didn't have time to finish it. She is an experienced Java programmer, but I am not. However, the app is small enough that it seemed like a project I could take on as my first Java app (I do work with JVM languages such as Clojure, so I have some background exposure to the world of the JVM).
I am adding the ability to output our data as JSON. I would like to use Google's Gson class:
http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.google.code.gson%22
com.google.code.gson
My co-worker had no outside dependencies so she was simply compiling the code from the command line. Now that I am adding 3rd party dependencies, I thought I should switch to a build tool. I choose Buildr : http://buildr.apache.org/extending.html
I decided to download the 3 Jar files that constitute com.google.code.gson:
gson-2.2.4-javadoc.jar
gson-2.2.4-sources.jar
gson-2.2.4.jar
I am not sure how to include them in my Buildr project.
I used the "buildr" command to establish the default directories that Buildr prefers. But there is no obvious folder for 3rd party Jars.
I tried many variations of my build file. My latest iteration is:
# Version number for this release
VERSION_NUMBER = "1.0.0"
# Group identifier for your projects
GROUP = "buildr_fdg"
COPYRIGHT = "2014, Open"
GOOGLEGSON = ['gson-2.2.4-javadoc.jar', 'gson-2.2.4-sources.jar', 'gson-2.2.4.jar']
# Specify Maven 2.0 remote repositories here, like this:
repositories.remote << "http://repo1.maven.org/maven2"
desc "The Buildr_fdg project -- creating JSON object full of fake data since we don't have enough real data ."
define "buildr_fdg" do
project.version = VERSION_NUMBER
project.group = GROUP
manifest["Implementation-Vendor"] = COPYRIGHT
compile.with GOOGLEGSON
resources
test.compile.with # Add classpath dependencies
package(:jar)
end
But I get these errors:
buildr build
(in /Users/cerhov/projects/openz/lofdg/buildr_fdg, development)
Building buildr_fdg
Compiling buildr_fdg into /Users/cerhov/projects/openz/lofdg/buildr_fdg/target/classes
/Users/cerhov/projects/openz/lofdg/buildr_fdg/src/main/java/Main.java:8: package com.google.code does not exist
import com.google.code.*;
^
/Users/cerhov/projects/openz/lofdg/buildr_fdg/src/main/java/Main.java:27: cannot find symbol
symbol : class Gson
location: class com.company.Main
Gson gson = new GsonBuilder().setPrettyPrinting().create();
^
/Users/cerhov/projects/openz/lofdg/buildr_fdg/src/main/java/Main.java:27: cannot find symbol
symbol : class GsonBuilder
location: class com.company.Main
Gson gson = new GsonBuilder().setPrettyPrinting().create();
^
Note: /Users/cerhov/projects/openz/lofdg/buildr_fdg/src/main/java/Main.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
3 errors
Buildr aborted!
RuntimeError : Failed to compile, see errors above
(See full trace by running task with --trace)
cerhov : 15:33:25 : ~/projects/openz/lofdg/buildr_fdg $ buildr build
(in /Users/cerhov/projects/openz/lofdg/buildr_fdg, development)
Building buildr_fdg
Buildr aborted!
RuntimeError : Don't know how to build task '/Users/cerhov/projects/openz/lofdg/buildr_fdg/com.google.code.gson'
How do I tell Buildr about my 3rd party Jars?
The simplest way to add dependencies to a Buildr project is to use the "maven" coordinates of the library. So I believe what you want to do is replace the GOOGLEGSON with something like
GOOGLEGSON = ['com.google.code.gson:gson:jar:2.2.4']
This combined with the reference to Maven central should mean that Buildr downloads the dependency and adds it to your classpath.

Categories