How to create jigsaw module in SBT? - java

I would like to use jlink for creating self-contained application packages for all platforms (darwin, linux, windows) from Scala source code. It seems that jlink only works with new (relatively) jigsaw modules - so I need to package my code as a module. In Java world it seems to be easily achieved by placing special module-info.java file to the package that will become a module.
I tried to follow intuition and just placed this module-info.java into src/main/java/my.package.name/module-info.java. Though this doesn't work. It seems that scalac is trying to read module-info.java as usual Java file (which is not the case), hence the error
module-info.java:1:8: illegal start of type declaration
[error] module my.package.name {
[error] ^
What do I need to do to package my Scala code as a module?
Open JDK: 11
Scala: 2.12.4
SBT: 1.1.6

In general seems like that scala doesn't completely support Java9+, at least their compatibility notes read so.
As of Scala 2.12.6 and 2.11.12, JDK 9+ support is incomplete. Notably,
scalac will not enforce the restrictions of the Java Platform Module
System, which means that code that typechecks may incur linkage errors
at runtime. Scala 2.13.x will provide rudimentary support for this,
but likely only in nightlies built on Java 11.
You can follow Support features of JDK 9+ and Java 11 testing for further updates.

Related

How to compile Java 9 and subsequent releases code in JDK8?

I have a maven aggregate project that contains api, application, domain, infrastructure and common-util modules.
The aggregate project JDK version is 17, but the common-util module alone uses JDK8 instead of 17 (for more compatibility).
All source code in common-util modules does not use Java 9 and subsequent releases' syntax, but this module uses the JDK HTTP Client provided since Java 11. The HTTP interface class has two implementation classes, Java11Impl and ApacheImpl, and the latter should be used for versions lower than Java11.
Now the problem is that I can't compile the module with JDK8, the compiler tells me package java.net.http does not exist.
Can I get the compilation done by javac options like -bootclasspath? How should I do this?

Why is Scala usually installed for each of your Scala projects rather than being installed system-wide?

I was wondering why https://www.scala-lang.org/download/ says
Scala is unusual because it is usually installed for each of your Scala projects rather than being installed system-wide.
Why is it not the case for Java? Can this way work for Java projects?
Thanks.
If you use SBT, on the basis of scalaVersion specified in project's build.sbt, it will treat Scala like other regular library dependencies and download them under
.ivy2/cache/org.scala-lang/scala-compiler
.ivy2/cache/org.scala-lang/scala-library
.ivy2/cache/org.scala-lang/scala-reflect
similarly to regular library, say, cats
libraryDependencies += "org.typelevel" %% "cats-core" % "2.0.0"
which would end up under
.ivy2/cache/org.typelevel/cats-core_2.13
We can also have system-wide installation of Scala under, say /usr/local/bin, however SBT will not use that and will read from ~/.ivy2/
One thing is that, when talking about Java we need to distinguish JRE and JDK.
The JRE has JVM, so it's only the runtime platform for Java bytecode, JDK has compiler and other development tools.
Scala instalation already comes with compiler, interpreter, etc.
Both can run their own compiled code, but Java needs additional jars on classpath to run Scala programs (nicely described here).
Another and probably the main reason behind having separate installation of Scala for each project is that Scala is not fully compatible between its versions, i.e. particular version of Scala needs specific version of libraries.
(where Java is backward compatible)

Migrating Java 8 project to Java 11

We have a repository built using Java 8. There are multiple rest services within the repository. We want to migrate to Java 11 and trying to figure out the best way of doing this. We are considering doing module by module. For example changing one service over to Java 11 while the remaining are still Java 8. We are unsure if Maven supports this?
Disclaimer: This is not an answer but just a partial report of my recent experience. Feel free to flag this answer if you feel that it doesn't meet the SO standards.
Does Maven supports this?
Yes, use the compiler plugin 3.8.0/3.8.1
However this migration requires addition care.
Recently we did something like this by migrating from ORACLE JDK 8 to OPENJDK 11. As we have houndreds of repositories with different missions, we faced all kind of problems. Just to cite some that I got here in my e-mail box tagged as [jdk11_migration]:
It is quite obvious but I'd like to highlight that in order to migrate from java 8 to 11 we have to meet the requirements from java 9 and 10 as well
Some maven plugins like cobertura do not support Java 11 and I guess they will never support it. In some cases, these plugins have reached the abandoned life cycle stage. The solution was looking for alternatives in a case to case manner. For example, we replaced cobertura by Jacoco.
rt.jar and tools.jar have been removed! Everything you have explicity refered from them will probably break.
some classes which we shouldn't use in java 9 or less now in java 11 no longer exist. I'm talking about to access classes in packages like sun.*, sun.misc etc. The solution is to look for a one-to-one replacement or refactor the code to avoid the usage.
Reflection usually is the last bullet to use and, for these cases, in java 9 and above we geta warning messages like:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ...
WARNING: Please consider reporting this to the maintainers of ...
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Although it is not exactly a solution, there is a flag to get rid of this warning --illegal-access=permit . This is particulary important when using surefire maven plugin.
Java 9 introduced the module system then "now" we have the phenomena of clash of packages. For example, messages like "The package org.w3c.dom is accessible from more than one module: , java.xml" . The solution is to find the source of reduntant inclusion (notably duplicated maven dependences or dependences of dependences) and remove it.
Althought it wasn't a problem for us, I just noted that your repository consists in REST components in majority. Probable you will face ClassNotFound issues regarding some packages like javax.xml.bind which were basically dropped out of java standard edition. You can fix it by including they explictly in your pom.xml.
Luckly you may find good questions & anwswers for each issue you will find in your migration here in SO or over internet. There are some migration guides in the wild which are good start points. Specific issues, like obfuscation and IDE integration, can take a little bit of time, but, at least in my experience, this migration was painless than I have supposed.
My suggestion is to upgrade the entire project. Try to have some Java8 and some Java11 modules can be very difficult. As you already know, starting from Java9 module appears. The answer is very generic, so it's difficult to give a detailed response. I suppose:
Your project is managed with maven
You have many artefacts (jar)
You are using some library or framework (who said Spring?)
You are using a Source Version Control (Git or Subversion for example)
You have a multi-module project
The code you wrote works on Java8 and on Java11 platform
My suggested plan:
Create a branch on your SVC for Java11 project's version and start to work on it.
Create a parent module for common definitions
Upgrade maven plugin and all your library to the latest version. For Maven compiler set the Java11 target (the Java11 is supported only by the latest version of Maven Compiler Plugin).
For each module define the exported packages (and specify which packages are required)
If there are many modules, start with only a few of them and then include the remains.
If it can help you, let have a look at this simple project on github (It target Java11 and it's a multi-module Maven project).
Hope it helps.

ASMifier class missing from ASM 3.3.1

According to the ASM FAQ, to get example ASM code, I should use the ASMifier class, like this:
java -classpath "asm.jar;asm-util.jar" org.objectweb.asm.util.ASMifier org/domain/package/YourClass.class
But that gets me the error:
Error: Could not find or load main class org.objectweb.asm.util.ASMifier
Looking at JAR files, the ASMifier class seems to be missing, though its helper classes are present:
./org/objectweb/asm/util/ASMifierClassVisitor.class
./org/objectweb/asm/util/ASMifierAnnotationVisitor.class
./org/objectweb/asm/util/ASMifierMethodVisitor.class
./org/objectweb/asm/util/ASMifierAbstractVisitor.class
./org/objectweb/asm/util/ASMifierFieldVisitor.class
This is with ASM 3.3.1, as provided by Fedora 20. Is the FAQ for a newer version, and I should be using different instructions? Did Fedora mess up the packaging (even though their bug-tracker shows nothing)? Something else?
When browsing the SVN repository of ASM, you can read up the revision history of the ASMifier: It was formerly known as the ASMifierClassVisitor which was also this utility's name in version 3.1.1.
ASM never had a reputation of maintaining binary or even compilation compatibility. Thus, you might encounter several problems like the one you describe when using non-bleeding edge versions of the library. (The authors promised to improve this after ASM's version four.) You, or the libraries that you use, should however always repackage ASM into a different namespace in order to avoid such issues. This is even recommended in the FAQ to using ASM.
For running your example, you would have to use:
java -classpath "asm.jar;asm-util.jar" \
org.objectweb.asm.util.ASMifierClassVisitor \
org/domain/package/YourClass.class

Why can't SBT find JavaFX packages in Java

I wanted to try and make a simple JavaFX app in sbt, but it seems sbt is unable to locate any of the javafx packages, giving me errors like
error: package javafx.application does not exist
error: package javafx.fxml does not exist
error: package javafx.scene does not exist
... and so on
And I find that odd given the fact that the javafx package is included in Java 7+ by default, so if anything, the packages SHOULD be available to the compiler, but it doesn't seem that way..
Any help?
ps: I'm not using any javafx related plugins, just pure sbt, and I'm trying to compile a Java project, not a Scala one. The project is set up to be compatible with Eclipse using sbteclipse
How to build something against JavaFX (in SBT or any other tool) depends a lot on your version of the JDK:
Using JDK 8
It all works out of the box: JavaFX is located in jre/lib/ext, which means it is on the default classpath of java and javac, and it should be available automatically both when compiling and running. That's the configuration #JacekLaskowski has in his answer.
This only works if you only target Java 8: JavaFX 8 is not available for Java 7, so compiling against it makes your app Java8-only (unless you make sure to only use things available in JavaFX 2.x, target jdk7 bytecode, package JavaFX 2.x with your app, etc.)
Using JDK 7u6+
The JavaFX SDK is distributed with the JDK, but it is not available automatically: it is not on the classpath of anything, you have to look for it in jre/lib and add it to the classpath by yourself. That's what some IDEs do automatically when they have JavaFX support.
SBT doesn't do that automatically for you. There is sbt-javafx that helps a little, but you still need to configure the location of jars, etc.
Using JDK 6 to JDK 7u5
You have to download the standalone version and add it to the classpath. The rest of the jdk7u6+ case above applies.
Finally, note that new features are added to JavaFX during the lifetime of Java 8, so building you app may require a specific version of JDK8 (this also happened a little in JDK7), and that's also one of the reasons you are supposed to package JavaFX with your application.
Basically as soon as you depend on JavaFX, you have to track the JDK and/or JavaFX itself as two unmanaged dependencies, with individual developers having to check versions and configure things.
That's odd as I'm new to JavaFX and have never worked with it before yet it works like a charm for me - at least I could import javafx.application package.
scala> import javafx.application
import javafx.application
You'd need to include more information about your environment. Mine's below.
> about
[info] This is sbt 0.13.5
[info] The current project is {file:/Users/jacek/sandbox/sbt-learning-space/}sbt-learning-space 1.0.0
[info] The current project is built against Scala 2.10.4
[info] Available Plugins: sbt.plugins.IvyPlugin, sbt.plugins.JvmPlugin, sbt.plugins.CorePlugin, sbt.plugins.JUnitXmlReportPlugin, com.typesafe.sbteclipse.plugin.EclipsePlugin, net.virtualvoid.sbt.graph.Plugin, com.timushev.sbt.updates.UpdatesPlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.4
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import javafx.application
import javafx.application

Categories

Resources