197

What is the relationship/difference between sourceCompatibility and targetCompatibility? What happens when they are set to different values?

According to the Toolchain and compatibility section of the Java plugin Gradle documentation:

  • sourceCompatibility is "Java version compatibility to use when compiling Java source."
  • targetCompatibility is "Java version to generate classes for."

My understanding is that targetCompatibility will generate Java bytecode that is compatible with a specific version of Java. Is this a subset of the functionality of sourceCompatibility?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Rylander
  • 19,449
  • 25
  • 93
  • 144

6 Answers6

128

targetCompatibility and sourceCompatibility maps to -target release and -source release in javac. Source is basically the source language level and target is the level of the bytecode that is generated.

More details can be found in the Cross-Compilation Options for javac section of Tools Reference for Java 8, for Java 11, for Java 17, or for Java 19.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Matt
  • 8,367
  • 4
  • 31
  • 61
  • 1
    The above link is pointing to doc for Java 7. I wonder if you want something like https://docs.oracle.com/en/java/javase/11/tools/javac.html#GUID-AEEC9F07-CB49-4E96-8BC7-BCC2C7F725C9 ? – Brian Agnew Feb 11 '20 at 10:09
96

Be careful when you use these; we've been bitten by people making assumptions.

Just because you use sourceCompability (or targetCompatibility) of 1.5 doesn't mean you can always compile your code with JDK 1.6 and expect it to work under JDK 1.5. The issue is the available libraries.

If your code happens to call some method that is only available in JDK 1.6 it will still compile with the various Compatibility options for the target VM. But when you run it, it will fail because the offending method is not present (you'll get a MethodNotFoundException or ClassNotFoundException).

For this reason, I always compare the Compatibility setting to the actual Java version I'm building under. If they don't match, I fail the build.

peterh
  • 11,875
  • 18
  • 85
  • 108
user1644873
  • 1,071
  • 8
  • 6
  • 5
    This is a subtle, but very important observation. – Natix Apr 08 '16 at 13:23
  • 2
    How do you compare them? – secondbreakfast Sep 20 '16 at 18:00
  • Why do you fail the build? The "bootstrap classpath" option is given just for mitigating this issue. You can always use the proper bootstrap and it should work just fine. – Codebender Nov 09 '16 at 15:30
  • 14
    `if(JavaVersion.current() != JavaVersion.VERSION_1_8) throw new GradleException("This project requires Java 8, but it's running on "+JavaVersion.current())` This is how I sort this issue out, right in the beginning of the build.gradle file. – xeruf Nov 06 '17 at 10:28
  • 3
    Since Java 9 there is now a new `javac` option `--release` intended to address this problem, by only allowing use of API available in the specified Java version. For more on this see https://stackoverflow.com/a/43103038/4653517 – James Mudd Mar 29 '19 at 09:05
  • @JamesMudd Wait, so before Java 9 we could use a method only available on Java 8 even though the compatibility was set to Java 1, for example, and the IDE wouldn't warn about that!? – Edw590 Sep 01 '21 at 00:04
  • Typically yes. When the IDE has a setting for language level it typically means the language constructs i.e. is a lambda valid etc. It does not know which methods were added to the standard libraries in which Java version. So it will just compile against the JVM in use by the IDE. If you want to ensure this use a JVM of the version you are targeting, and don't rely on these version options. – James Mudd Sep 01 '21 at 09:05
48

sourceCompatibility = specifies that version of the Java programming language be used to compile .java files. e.g sourceCompatibility 1.6 =specifies that version 1.6 of the Java programming language be used to compile .java files.

By default sourceCompatibility = "version of the current JVM in use" and targetCompatibility = sourceCompatibility

targetCompatibility = The option ensures that the generated class files will be compatible with VMs specified by targetCompatibility . Note that in most cases, the value of the -target option is the value of the -source option; in that case, you can omit the -target option.

Class files will run on the target specified by targetCompatibility and on later versions, but not on earlier versions of the VM

A Jakhar
  • 706
  • 7
  • 8
2

In my opinion, “sourceCompatibility” means the what feature you can use in your source code.For example,if you set sourceCompatibility to 1.7, then you can't use lambda expression which a new feature in java 8 even though you jdk version is 1.8.
As for “targetCompatibility”, it means which version of jre the generated class file can be run on, if you set it to 1.8,it may not run successfully on jdk 1.7, but it can usually run on higher version of jdk.

haoyu wang
  • 1,241
  • 4
  • 17
2

There have been given a lot of good explanations of what sourceCompatibility vs targetCompatibility is good for and a further good article can be found here Gradle: sourceCompatiblity vs targetCompatibility. But instead of sourceCompatibility vs targetCompatibility I would suggest to use the Gradle toolchain (see Toolchains for JVM projects) which makes release or sourceCompatibility tweaks obsolete and gurantees that langauge-features (sourceCompatibility), bytecode (targetCompatibility) and Java-API/-Libraries (release) will match the Java Version. (Only drawback is that the IDE support is not yet fully established but is on its way).

becke-ch
  • 413
  • 4
  • 8
  • A reference on "toolchains making `release` or `sourceCompatibility` tweaks obselete": https://blog.gradle.org/java-toolchains. It took me some time to find this. – Shreck Ye Jan 13 '23 at 14:46
0

These are the flags for the javac command.

javac [options] [sourcefiles]

Options:
...
-source release - Specifies the version of source code accepted.
...
-target release - Generates class files for a specific VM version.
...

In other words: you write a code in a source version and compile your classes to the target VM version. In order to run it e.g. on other workstation with older java version.

According to: https://docs.oracle.com/en/java/javase/11/tools/javac.html

Benjamin
  • 3,217
  • 2
  • 27
  • 42