For some reason I cannot use the keyword var despite being on language level 13.
Settings -> Build, Execution, Deployment -> Compiler -> Java Compiler
Is set to 13.
I am using gradle with the JVM language targets set to 1.8
I checked and tried:
problem in compile time when using "var" in jdk 11
How to avoid IntelliJ to reset language level?
You didn't say what IDE you are using, but I am guessing IntelliJ. You also didn't show the Gradle configuration in IntelliJ, so I am assuming you are going by the default settings and that its a relatively new version.
You can chose between having IntelliJ compile your source code, or let Gradle do it. The default is Gradle, so it doesn't matter what how you configure the IntelliJ compiler as it isn't used.
If you don't fork the Gradle compilation, it will use the same JDK for compilation as for running Gradle. In IntelliJ, this is configured in the Gradle JVM setting under Build Tools -> Gradle (or JAVA_HOME if you are running it from the CLI).
Now back to your question. The reason you can't use the var keyword is exactly because you have configured it to target Java 8. That means the source also have to be compatible with Java 8. If you think about it, newer language features usually require newer versions of the byte code. So if you need your final binary to be compatible with Java 8, you need the source to be compatible with Java 8 as well.
You can still use Java 13 to compile to Java 8 byte code (as long as you program against a Java 8 API and syntax). But instead of just the "target" version, you should use the --release flag as this will also configure the bootclasspath correctly, which I am guessing you didn't do (this ensures that you use the correct API). For instance:
compileJava {
options.compilerArgs.addAll(['--release', '8'])
}
Related
Recently, a teammate used the following function in our Java 8 code: Matcher.replaceAll​(Function replacer).
The function was introduced in Java 9, but because he is using a newer compiler, the API function was simply found in the JDK's rt.jar and nobody noticed this won't work under real Java 8 environments.
The compatibility settings are correctly set, and the gradle subproject has the following settings:
sourceCompatibility = 1.8
targetCompatibility = 1.8
I had very similar issues at the time when I first used the Java 6 function String.isEmpty in Java 5 code - the code made it into the release and crashed there.
What can I do to enforce the usage of the correct API. As it is a shared library, do I have to use (and install, maintain..) a different JDK for this gradle subproject, or is there some kind of compatibility scanner which runs through a built jar and checks all rt references?
As you've noticed, the two compatibility configurations does not consider the APIs of older versions - only the syntax, semantics and the resulting byte code.
There are two options you can take. One is to have JDK 8 installed on your computer, and the configure Gradle to use it when compiling your project. It looks like this:
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.executable = "$java8Home/bin/javac"
options.bootstrapClasspath = files("$java8Home/jre/lib/rt.jar")
}
The disadvantage here is that you will need to have JDK 8 installed in the first place, and as it will probably be installed in different locations, you will need probably want to configure it with an environment variable or property (I've called it java8Home here).
However, since Java 9, the JDK now knows about the documented APIs of previous versions, and you can select which one to use with a new --release flag. This is not going to work if you use undocumented APIs, but it means you can compile your project with any versions of Java and still make the resulting classes compatible with Java 8. You can do it like this:
tasks.withType(JavaCompile) {
if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
options.compilerArgs.addAll(['--release', '8'])
}
}
Note that the 'if' statement is only there in case you still need to support running Gradle with Java 8 (through your JAVA_HOME variable). If you are only using later versions, it can be removed so you always set the 'compilerArgs'.
For some versions of Java, it is possible build Java code on a newer JDK to run on an older JDK / JRE. You have already discovered the --source and --target options for javac and the corresponding Gradle settings. The other thing you can do is to use --bootclasspath to tell javac to compile against the runtime libraries for an older version of Java.
Since you are using Gradle, check out "gradle-java-cross-compile-plugin" (https://github.com/nebula-plugins/gradle-java-cross-compile-plugin). I can't find any documentation for it, but it apparently deals with --target and --bootclasspath.
Having said that, I don't think cross-compiling Java is a good solution.
I would actually recommend that you set up a Continuous Integration (CI) server (e.g. Jenkins) with JDK installations for all of the Java versions you are interested in supporting. Then set up jobs to build your code and run your unit tests for each Java versions.
Note that simply compiling your code against the older Java libraries is not sufficient to verify backwards compatibility. Sometimes the behavior of libraries changes. You need to run your tests, and your tests need to cover the cases where compatibility issues may exist.
On our hadoop cluster my Pig UDF fails complaining
[main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1069: Problem resolving class version numbers for class <classname>
I read writing a udf in pig kind of like tutorial and the problem seams to be clear, but unfortunately I cant solve it. My manifest does not contain a version (is this necessary?) and javap reports major version 52, representing java 1.8, although I compiled it with 1.7. So how can I solve this?
My manifest does not contain a version (is this necessary?)
The version manifest entry is not relevant to this. The classloader pays no attention to the version manifest entry.
and javap reports major version 52, representing java 1.8,
That is the relevant fact.
although I compiled it with 1.7.
This all boils down to how you compiled your code, and I think you are incorrect when you say that you compiled with Java 1.7.
Why do I say that? Because the Java 1.7 java compiler is not capable of creating a ".class" file with the Java 1.8 version numbers. It simply doesn't understand the Java 8 syntax extensions, and the corresponding enhancements to the classfile format.
So how can I solve this?
The way to resolve this is to look carefully at your build process and figure out how and why the offending class got compiled using a Java 1.8 compiler. Because there can be no doubt that that is what has happened.
If you are building by hand (e.g. by running "javac" and "jar" from the command line, or by clicking buttons in your IDE) then now would be a good time to learn about build tools like Maven, Ant and Gradle.
FOLLOWUP
That not true. My setting proofs this, but I guess I found the issue: .settings/org.eclipse.jdt.core.prefs contain several 1.8. entries. This may be due to the fact that at the time of the project creation I had 1.8. installed.
Actually, it doesn't "prove" anything ...
What this is telling me is that you are probably compiling with the Eclipse Java compiler, not the Java compiler from your JDK.
In fact, your Eclipse compiler is (or was) compiling for a Java 1.8 target ... because that is what your Eclipse settings say that the Eclipse Java compiler should do. If you are using the Eclipse compiler to compile your code, the version of your JDK or JRE install doesn't determine the classfile version number.
Once again, I strongly recommend that you learn to use a Maven, Ant or Gradle so that you build process is more repeatable and less error prone.
I guess Stephen C's is the most general answer.
In my special case the problem was, that the project specific compiler compliance settings were wrong, because I used JDK 1.8 locally when I created the project and installed 1.7 later, when I got the error on the cluster.
The option is quite hidden and can be found here:
Window > Preferences > Java > Compiler > "Configure project specific settings" > [projectname] > "Compiler compliance level"
For some time I tried to understand, but I still don't get exactly what "compiler compliance level" for a project in Eclipse means. I looked all over this site and Google and couldn't find an answer I could understand.
Let's say I want my program to be able to run on JRE 6.
I can do: Project > Preferences > Java Build Path > Libraries, and set the JRE library I use to JRE 6.
Why isn't this enough?
I never understood why I also need to set the compiler compliance setting to JRE 6.
I'd like to understand the difference between using JRE 6 in a project, and setting the project's compiler compliance setting to JRE 6.
What exactly does compiler compliance level mean?
The compiler compliance setting tells the compiler to pretend it's a different version of Java.
The Java 8 compiler will produce class files in the Java 8 version of the class file format, and accept Java 8 source files. JRE 6 can't load this version, because it was created after JRE 6 was.
If you set the compliance level to "JRE 6", it will instead compile Java 6 source files into Java 6 class files.
It's like saving a Word document as "Word 97-2003 format" - so that Word 97-2003 can read your document. You're saving the class files in Java 6 format so that Java 6 can read them.
It tells you what version of the JDK you are adhering to; specifically, which JRE are you targeting with your build.
It is the MINIMUM JRE needed to run your code
The Java compiler can compile code that will run on prior versions of the JVM. Even if you have JDK 6 installed, you could be writing code targeted for people that use JDK 5. The Compiler Compliance level tells Eclipse to use appropriate settings when compiling your project to ensure you code will work on the target JVM you specify. By default, if I recall, Eclipse picks Java 5 Compliance. If you want to use code features specific to Java 6 or Java 7, you will have to change the compliance level.
The simplest way to describe the "Java compiler compliance" setting is that it determines which Java Virtual Machine instructions may be used in the "compiled" Java code ... and which library class versions are to be used. Each release of the JVM (and its libraries) may introduce new instructions (the VM) or adjust the class libraries that are delivered along with the JVM.
You should set the setting to the lowest level of JVM that you expect your product to be run on.
I decided to give Eclipse (Eclipse 3.7.2 ) a chance because of the plugin "Columns For Eclipse". The IDE I would like to migrate away from ( Visual Slickedit ) has spoiled me with sophisticated column editing features and this plugin has most of them, whereas the default column editing features in Eclipse are too basic for me.
I tried the plugin out at home and I really like it. However, the machine I use at work runs on Java 1.5 and the plugin requires Java 1.6.
I would like to try recompiling the plugin under Java 1.5, as my job uses WebLogic 9.2 which runs on Java 1.5. I don't want to risk compatibility issues by setting up my computer to run on Java 1.6
I have the source code, but it didn't come with directions on how to compile the plugin. It isn't structured in a Maven project.
I'm 100% new to Eclipse so I was wondering if someone could give me step by step instructions for compiling (and installing ) my own copy of the plugin under Java 1.5.
Alternately, is it possible to set up Eclipse 3.7.2 to run on Java 1.6 but always compile in Java 1.5?
Thanks much in advance.
Building and installing the plugin without an existing build script would be quite complicated. For your second option, you can setup the compiler compliance level for the entire IDE:
Or alternatively, you could set it up on a project-by-project bases (Right click project, Properties->Java Compiler).
Yes, it is possible to run Eclipse with Java 6, but use a Java 5 JDK as the default for compilation and runtime. You need to configure Eclipse: Window -> Preferences -> Java -> Installed JREs.
You can also use Java 6 as the development/runtime and set the compiler compliance level to 1.5 (same as 5), but that's a bit dangerous as it doesn't stop you using APIs only available in Java 6; it only enforces language syntax.
I am trying to config my eclipse (Helios) use jdk 7 to compile my code. I didn't install jdk 7 on my Windows XP. But I include all of the jdk contents with my project. It seems the solution provided in this post doesn't work. Compile java code needs JDK. the JRE is enough for running the compiled code. I think we need a way to configure the JDK to be used not just JRE. I tested with a JDK 7 new feature, String in switch, I can compile it in my batch file compile system but cannot use eclipse to compile it.
any idea?
This is what I did to make Eclipse 3.x works with Java 7.
install Java 7 in another machine and then copy the JDK folder into my java application 3rdparty directory (so my machine still use Java 6);
download the Eclipse 3.7.1 from here: eclipse 3.7.1
configure Eclipse by following steps in this post (select 1.7 in Compiler compliance level under the Java Compiler entry);
At least I can use String in Switch now in Eclipse.
Good luck.
Compile java code needs JDK. the JRE is enough for running the
compiled code.
that is right
"But I include all of the jdk contents with my project"
Including those will not change eclipse's compiler behavior. Including files under project build path just makes those classes available for your application development/run-time (or as good as setting CLASSPATH)
Do these :
1 - Install required version of JDK
2 - Choose following menu - Window > Preferences > Java > Compiler - and you will see a drop down to choose the version you want to use.
3 - Read this and this as well.
Good luck for being DBA after 5 yrs. Please consider working on your English as well (no offense please)