Idea 15 javac compiler



I am working on a very old project, which uses java 1.5, I have set java 1.5 in project properties, set javac compiler version 1.5, but when I press ctrl+shift+F9 (compile) I see a message "Information:Using javac 1.8.0_65 to compile java sources". I cannot understand why compiler uses 1.8 java, my java_home is 1.5 and all project setting are set to java 1.5 as well.

Comment actions Permalink

Hi Igor,

Although javac 1.8 is used (from the VM on which IDEA runs), the compilation is done against the classes that are set in your project settings and with the language level and target bytecode version that you have set. So if JDK 5 is set as your project JDK, you will get classes that are 100% compatible with java 5 platform. Such compiler version limitation exists because of compiler tool API IDEA uses to integrate compiler. This API is available starting from java 6.

I'd like to emphasize it once again: IDEA uses compiler ( a tool) of version 1.8, but name resolution, linking and bytecode generation are done against java 5 libraries from your project's classpath by means of javac's cross-compilation capabilities. Not only java 5 is supported as a target platform, but all java versions, including java 1.

Hope this helps,
Best regards,

Comment actions Permalink

The problem is that when I compile my project from command line with 1.5 java compiler I get error with generics (I've accidently used some feature which is not supported by java 5), when Idea compiles my project I don't get this error. For me it is unconvinient, because when I set all settings to java 5 in IDE, I expect that it compiles classes against java 5 and won't let me commit buggy code.

Comment actions Permalink

It looks like language level and bytecode target level are not set to 1.5. Then any attempt to use generics will cause compilation error.

Could you please send me your project configuration files (.idea directory or the .ipr fiels and all iml files)?
If you are able to reproduce the absence of errors on a hello-world project, please sent this project to me for investigation.

Comment actions Permalink

I have added test project in, and my real project .idea folder in and project iml.

In my test project I put all classes together to make compilation process easier from command line. Idea compilation says all is ok, when I try to compile from command line I get

C:\Users\igorz\IdeaProjects\generics\src>C:\Oracle\Middleware\jdk150_12\bin\javac C:\Users\igorz\IdeaProjects\generics\src\ -g -nowarn -target 1.5 -source 1.5 -encoding utf-8
C:\Users\igorz\IdeaProjects\generics\src\ type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Object
    response = message.getResponse();
Note: C:\Users\igorz\IdeaProjects\generics\src\ uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

Comment actions Permalink

That can happen even if the compiler and language level are set correctly.

Say the 1.7 API adds a call X#y(Z z) where 1.5 only had X#y().
The 1.8 compiler, even with 1.5 language level set, won't complain about that, but when running against a 1.5 runtime (which of course lacks that call) you will get a runtime exception.

That's why it's always a good idea to compile using the actual compiler version you will be running against.

Comment actions Permalink

Yeah, but I expect my IDE to compile my project with appropriate compiler version to avoid such bugs, even when IDE is not free.

Comment actions Permalink

Jeroen, this is a different case.

> Say the 1.7 API adds a call X#y(Z z) where 1.5 only had X#y().

In my original post I deliberately mentioned it twice that the name resolution is performed against java 5 libraties. This means that if there is no such call in java 5 platform, it won't be resolved.
It is a very common mistake to think that specifying -source and -target options is enough for correct cross-compilation. As you correctly mentioned, one need also to instruct compiler to resolve against correct platform classes. This is achieved by specifying "-bootclasspath" compiler option (don't mistake with the "-bootclasspath" JVM runtime option).

Comment actions Permalink

Thanks for the information, Igor.
Did some research on that.
The problematic line here is

T response = message.getResponse();

Javac 1.5 indeed fails to compile this code, while javac 1.6 and higher work fine and produce bytecode that is 100% compatible with java 1.5.

Generics specification for java 1.6 did not introduce any changes in type inference in comparison to java 1.5, so here we have type inference - related compiler bug, which, unfortunately won't be fixed in java 5 SDK versions. However, the bug is fixed in java 6+ versions.The only way to workaround the bug is either to use the tool where it is fixed (javac 1.6 or higher), or explicitly specify expected type in the code to help compiler:

T response = message.<T>getResponse();

This syntax fixes the problem for javac 5, though it is redundant according to specification.
The lack of compiler tool API in java 5 or older versions forces IDEA's build to use javac 1.6 or higher. This, of course, imposes another limitation, that we do not support older versions of javac compiler (with all their bugs). We do not consider this as a big issue, since development for all java versions, including java 5 is still fully supported and with better (and newer) compilers, which have many issues found in their previous versions fixed, especially related to generics.

Comment actions Permalink

You're confusing your compiler with your API.
It uses the correct compiler correctly, generating class files of the correct version (try compiling something with annotations to 1.4 language level and it will fail even if you use a 1.8 compiler), but it uses the core API of the JDK you're telling it to use, which is the 1.8 API if you're using the 1.8 compiler.
Then you're running those classes against a 1.5 compiler which of course lacks the specific call you were erroneously using, and you get a runtime exception. Which is what you'd expect if you're running against an older version of any API from the one you compiled against.
The compiler has no way of knowing what was available and what wasn't in an older API after all.

Comment actions Permalink

it isn't. Not at compile time.
The compiler ALWAYS uses the core API jars from its own distribution for name resolution. Those are the jars that are loaded when loading the compiler itself, which is a Java process.

Comment actions Permalink

I have the same problem, but in reverse.  I have old code that is compiled to 1.5 and I set the SDK to 1.5 in intellij's settings for the project and all modules.   The problem is the code implements some java interfaces and since it uses 1.8 to compile, there are new methods in the 1.8 interfaces that are not implemented in the code.  Thus it fails compiling.  I don't understand why you can't use the compiler set for the JDK for the project or module SDK.  I'm using IntelliJ 14.   Here is my output and this compiles fine if I use the 15 SDK outside of IntelliJ...

Information:Using javac 1.8.0_121 to compile java sources
Information:java: Errors occurred while compiling module 'product'
Information:4/19/2017 11:35 AM - Compilation completed with 100 errors and 3 warnings in 24s 770ms
Warning:java: source value 1.5 is obsolete and will be removed in a future release
Warning:java: target value 1.5 is obsolete and will be removed in a future release
Warning:java: To suppress warnings about obsolete options, use -Xlint:-options.
Error:(103, 45) java: m_owner has private access in com.f1j.util.IndexableImpl
Error:(515, 24) java: com.f1j.util.ShareableConst cannot be inherited with different arguments: <> and <com.f1j.util.SharedConst,com.f1j.util.Const>
Error:(172, 33) java: m_height has private access in com.f1j.impl.paint.AbstractFont
Error:(173, 37) java: m_isBold has private access in com.f1j.impl.paint.AbstractFont
Error:(174, 39) java: m_isItalic has private access in com.f1j.impl.paint.AbstractFont
Error:(175, 40) java: m_underline has private access in com.f1j.impl.paint.AbstractFont

Comment actions Permalink

>  The problem is the code implements some java interfaces and since it uses 1.8 to compile, there are new methods in the 1.8 interfaces that are not implemented in the code.

You effectively say that the code being compiled is resolved against javac 1.8 runtime. It does not work this way (see the discussion above, why). Your project code is linked against JDK1.5 provided this JDK is configured in the module's dependencies.

The problem here is in compiler itself: javac8 applies stricter rules to generics than javac6 and javac5. Javac8 fulfills generics specification better than javac5, so generics-containing code compilable by javac5 may indeed not compile with javac8. So to fix this particular problem we need to use a different compiler version. There are several ways to achieve this:

1. If you are using IDEA 14, you can run it with java6 instead of java8. This way javac6 will be used to compile your project and it should compile fine, since javac6 is similar to javac5 in terms of generics processing.

2. Set your project JDK to java6, but live java5 for all modules that have java5-compliant code. In this case javac6 will also be used for compilation

In both cases your code will be linked against the jdk that is configured in module's dependencies (i.e. java5)

Comment actions Permalink

But I did have the Project JDK set to 1.5 and it was still using 1.8 to compile, why?   When I set the project JDK to 1.6 it works - thanks.

Comment actions Permalink

> But I did have the Project JDK set to 1.5 and it was still using 1.8 to compile, why?

Because compiler API to launch compiler exists from java version 1.6. When project used only 1.5, IDEA had to use compiler from its own runtime, which was 1.8. 


Please sign in to leave a comment.