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.
Related
I am migrating Java 1.8 to OpenJDK 11. Getting some dependency errors.
"sun.security.x509" is not visible.
BASE64Encoder error
How can I resolve these? I am using Apache Ant for build.
We can't tell you how to address the first problem since you haven't shown us the code where you are using classes in the sun.security.x509 package. A possible workaround might be to use --add-exports and/or --add-opens as described in this blog post:
All You Need To Know For Migrating To Java 11
However, that work-around is liable to stop working in the future. The solution would be to find a way to avoid depending on those classes.
The second problem can be used by rewriting your code to use the java.util.Base64 class (javadoc) that was introduced in Java 8.
I am using Apache Ant for build.
That is not directly relevant. The root cause of the problem is in the code you are building not the build tool you are using.
Background:
We have maven-based java project, which targets JRE 1.7, but the source code uses lambdas, so we use retrolambda for transforming Java 8 source code to Java 7. Also we use StreamSupport backport library when we need streams, function.*, Optional, etc.
Usage of retrolambda involves configuring the project's both source and target language level to 1.8.
Everything works fine if there are no dependencies on java8 classes or methods (like java.util.stream.*, java.util.Optional, or methods introduced in java8 like Collection.forEach). If there are such usages then build passes, but it fails in runtime, when running under JVM of Java 8.
Question:
My goal is to fail the build in case when such dependencies exist. Is there any way of detecting dependencies on new Java 8 classes/methods in build-time?
I thought about 2 possible options, but I'm not sure whether either of them is doable:
Some kind of bytecode analyzer for detecting depdencies on predefined classes and methods. Are there such tools/maven plugins?
Lint (lint4j) rules. Not sure whether it's possible to detect dependency on class/method using lint
You can use the Animal Sniffer Maven Plugin for this. It allows you to check that your code only uses APIs from a specified baseline (called the "signature"). In your case you'd use the org.codehaus.mojo.signature:java17:1.0 signature.
As others pointed out, you also could set up the bootstrap classpath, but that a) requires a JDK 7 to be set up and b) makes the build a bit more complex as you need to point to the JDK 7 install. Animal Sniffer is is much easier to work with in my experience.
How I can make maven to download only java 1.6 compatible libraries?
I have tomcat 6 and java 1.6.0_38. Or how I can find incompatible libs?
http://pastebin.com/WnwZL2RX list of dependencies.
If it's a one-time task which you have to run over the list your have provided then I would propose a manual approach described here:
What version of javac built my jar?
As for automatic check then you would have to implement your own maven plugin which will use similar approach to the one described above or drill into JAR manifest in order to get the Java version.
A very interesting question i hope to be able to check back for a more satisfying answer.
Maven is not able to perform such a task - and as faar as i know (i only checked back with a 5 minute websearch) there is no plugin available for this task.
In the end Maven supports with the dependency management by resolving dependencies of dependencies and has default approaches when it comes to versions of the same dependency ("the closest version wins") - regardless of this you will be in charge when it comes to compatibility between your own source and third party source.
Especially when talking about runtime incompatibility this could be a quite hard task to find out about issues.
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
I need to add some jars from JRE7 library to my Android project. But for example rt.jar is in conflict with android.jar from Adroid 2.2 SDK, so I get this error:
Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.
This is often due to inadvertently including a core library file
in your application's project, when using an IDE (such as
Eclipse). If you are sure you're not intentionally defining a
core class, then this is the most likely explanation of what's
going on.
However, you might actually be trying to define a class in a core
namespace, the source of which you may have taken, for example,
from a non-Android virtual machine project. This will most
assuredly not work. At a minimum, it jeopardizes the
compatibility of your app with future versions of the platform.
It is also often of questionable legality.
If you really intend to build a core library -- which is only
appropriate as part of creating a full virtual machine
distribution, as opposed to compiling an application -- then use
the "--core-library" option to suppress this error message.
If you go ahead and use "--core-library" but are in fact
building an application, then be forewarned that your application
will still fail to build or run, at some point. Please be
prepared for angry customers who find, for example, that your
application ceases to function once they upgrade their operating
system. You will be to blame for this problem.
If you are legitimately using some code that happens to be in a
core package, then the easiest safe alternative you have is to
repackage that code. That is, move the classes in question into
your own package namespace. This means that they will never be in
conflict with core system classes. JarJar is a tool that may help
you in this endeavor. If you find that you cannot do this, then
that is an indication that the path you are on will ultimately
lead to pain, suffering, grief, and lamentation.
I know there have been several threads about it and things like JarJar, OneJar or FatJar might be good for me. But I don't know how to make any of them work and documentation doesn't really make it clear (for me). I guess they use Ant commands, but I have always used Eclipse built-in builder and now I have no idea how to use neither Ant nor any of mentioned above.
So my question is: how can I repack this rt.jar so I could compile it in my Android project?
Thank you!
EDIT:
Ok, so what I want to achieve is to create a .jar, which can be used during developing Android application (simplifies some functionalities, doesn't really matter). But I would also like to be able to add the very same .jar to standard Java project in order to use some functions there as well. It would look like this:
Whoever writes an application adds this .jar to his Java project -> it enables him to generate certain files (internet is needed to do it) -> these generated files are then added to Android project -> later on, when somebody uses this Android app, these files provide certain functionalities without using internet (off-line).
It would be ill-advised to do this in any project at all, even if it were possible. You would be opening yourself to a wealth of class incompatibility and loading problems. But in any case it doesn't even matter because the core Java libraries are loaded way before your archives are even touched, making any such attempt at overriding them moot.
Not to even talk about the fact that Android is using its own JVM implementation which is not fully compatible with JDK 6 (forget JDK 7). Also note that it may be a copyright violation to package the core Java libraries with your code and could change your licensing options (IANAL).
You need to find another way to resolve whatever issue you are having (which you failed to mention in your question).
There are many JARs that work nicely on both Android and on classic Java. None involve having Android developers pirate rt.jar. Stick to java.* and javax.* classes that exist in both the Android SDK and in whatever level of Java you are supporting, and your JAR will work fine in both environments.
You should ideally refrain from using such .jar files, but if you must, you can add them to build path. But this, at times results in a conflict, like the one that you are facing right now. What you need to do to resolve this kind of a conflict, is:
add the jar in the build path.
Check "referenced libraries". The jar file should appear under the same.
once it features under referenced libraries, check the "android dependencies" virtual directory. If you get to see that you have an instance of the same jar file there as well, you should delete the "android dependencies" folder altogether. (Trust me, this does not affect your project in any way).
having done that, you should be able to compile your code without any further conflicts.
Happy coding.. :)