7

I am using below maven compiler plugin to compile my java code:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <inherited>true</inherited>
    <version>2.5.1</version>
    <configuration>
        <source>1.6</source>
        <target>1.6</target>
    </configuration>
</plugin>

My java_home points to Java 7.

My first question, will my classes be compiled with java 6 or java 7?

If with java 6 (because of <source>1.6</source> ), how maven will know the path java 1.6 as java home points to 1.7?

If I need to compile the source code with java 1.8, do I need to set source and target as 1.8?

But then, how maven will know that jdk 1.8 is in the path?

Do i need to change java_home to point to java 8?

hooknc
  • 4,854
  • 5
  • 31
  • 60
emilly
  • 10,060
  • 33
  • 97
  • 172

2 Answers2

7

Short answers:

  1. Since JAVA_HOME points to Java 1.7, the javac program (the compiler) from Java 1.7 will be used. However, since the source and target are both 1.6, the command mvn compile will generate classes that are runnable on JRE 1.6. This would be evident if you saw the major and minor version number associated with the generated class file using the javap utility. For Java 1.8, these values are 52 and 0, for Java 1.7, they are 51 and 0 and for Java 1.6 they are 50 and 0. You might wonder why you would ever want a Java 1.7 compiler to generate classes with target = 1.6. The reasons are based on the runtime (JRE) that you want to run the classes on. If your compiler and runtime always agree on the version, you may not use these, but these upgrades need to be coordinated in large teams and in the meanwhile, you should always try to remain as close to the latest versions of the software (one major reason: you want to get the bug fixes). The other thing to keep in mind is that source release 1.n requires target release 1.n.

  2. Yes, change those values <source> and <target> to 1.8 (there's perhaps a shortcut, but let's do that later ;)). Make sure that JAVA_HOME (and PATH) points to JDK 1.8, since the maven-compiler-plugin ultimately delegates to the javac program in the PATH with -source and -target arguments that come from the plugin's <configuration>. See the output of mvn -X compile, you will get something like:


[DEBUG]   (f) source = 1.8 
[DEBUG]   (f) staleMillis = 0 
[DEBUG]   (f) target = 1.8 
[DEBUG]   (f) useIncrementalCompilation = true 
[DEBUG]   (f) verbose = false 
[DEBUG] -- end configuration -- 
[DEBUG] Using compiler 'javac'.

Beware the following warning from Maven docs:

Merely setting the target option does not guarantee that your code actually runs on a JRE with the specified version. The pitfall is unintended usage of APIs that only exist in later JREs which would make your code fail at runtime with a linkage error. To avoid this issue, you can either configure the compiler's boot classpath to match the target JRE or use the Animal Sniffer Maven Plugin to verify your code doesn't use unintended APIs.

Andreas
  • 154,647
  • 11
  • 152
  • 247
Kedar Mhaswade
  • 4,535
  • 2
  • 25
  • 34
  • When i run `javap -verbose MyController | findstr "major"`, it returns major version: 50. so looks like compiler 1.6 is used inspite of javahome pointing to java 1.7 why ? – emilly May 02 '16 at 17:19
  • Because `source`, `target` are set to `1.6` which means the Java 7 compiler produces bytecode for JVM 6 – khmarbaise May 02 '16 at 17:21
  • No, it uses the compile from Java 7, but the compiler can produce bytecode which is compatible with Java 6. – dunni May 02 '16 at 17:21
  • @emilly, the compiler 1.6 is not used, but the compiler from 1.7 is used with `-source 1.6` since you asked that it does so. If you leave out `-source`, the default value will be 1.7 for 1.7 compiler, 1.8 for 1.8 compiler and so on. Make sure that `target >= source` – Kedar Mhaswade May 02 '16 at 17:23
  • @khmarbaise As you said `Because source, target are set to 1.6 which means the Java 7 compiler produces bytecode for JVM 6` . But as `javap -verbose MyController | findstr "major"`, returns major version as 50. Does not it should return major version as 51(value of java 7 compiler) as major value tells which compiler was used ? Agreed it will produce the bytecode for JVM 6 as I mentioned target as 1.6. – emilly May 02 '16 at 17:44
  • @KedarMhaswade Your answer was good, so I didn't want to create a new one. Hope you don't mind me adding to your answer. – Andreas May 02 '16 at 17:44
  • @emilly, no major value does _not_ "tell which compiler was used". It simply tells us the _major version of the class_ on which javap was run. Since Java takes backward compatibility seriously, `javac` from 1.7 _can be asked to generate classes_ that run on JRE 1.6, or JRE 1.5 and so on. – Kedar Mhaswade May 02 '16 at 17:53
  • @dunni Can you please have a look at mine latest comment – emilly May 02 '16 at 17:53
  • @Andreas, no problem, thanks. It was not terribly clear to me if we should bring in the complexity w.r.t. animal-sniffer-plugin for this question's answer, but perhaps you are right. – Kedar Mhaswade May 02 '16 at 17:58
  • @KedarMhaswadeBut what does major version indicates ? – emilly May 02 '16 at 18:04
  • @emilly see https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html for details. – Kedar Mhaswade May 02 '16 at 18:07
  • Thanks Kedar. Basically major version indicated which specific jvm it can run or compatible – emilly May 03 '16 at 07:30
-1

Maven uses the JDK which is been set in JAVA_HOME. You can set in mvn.bat to look for a specific JDK location.

atr
  • 684
  • 6
  • 10
  • 1
    Do not change `mvn.bat` or `mvn`. You should use as you mentioned `JAVA_HOME` or you can use `.mavenrc` file where you set `JAVA_HOME` (on Windows mavenrc_pre.bat` in home folder.). Or you can use [toolchain to define the JDK which is used](https://maven.apache.org/guides/mini/guide-using-toolchains.html). – khmarbaise May 02 '16 at 17:20