Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8338852

javac: tighten the specification and implementation of 'newer' for '-Xprefer:[source, newer]'

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • 9, 11, 17, 21, 24
    • tools
    • 9

      The [`javac` specification](https://docs.oracle.com/en/java/javase/22/docs/specs/man/javac.html) for '-Xprefer:[source, newer]' reads as follows:

      > '-Xprefer:newer': Reads the newer of the source or class files for a type (default).

      This leaves the case unspecified, where the class and the source file have the same time stamp.

      Up to and including JDK 8, `javac` chooses the `.class` file over the `.java` file if both are present and have the same time stamp. Starting with JDK 9 and later, `javac` chooses whatever comes last in the search path. If e.g. a `.jar` file on the classpath contains both, a `.class` file and a `.java` source file for the same class, then if the `.java` file comes first, `javac` from JDK 9+ behaves exactly like `javac` from JDK 8 and will not compile the `.java` file from the `.jar` file. Only if the `.java` file comes after the corresponding `.class` file, then the behavior of the JDK 9+ `javac` differs from that in JDK 8 in that it will choose to compile the `.java` file from the `.jar` file and place the resulting `.class` file in the output directory.

      This can easily be reproduced with the following example code:

      ```
      $ mkdir test && cd test;
      $ echo 'public class A { static final String S = "A"; } ' > A.java
      $ javac A.java
      $ touch -t 03210321 A.java A.class
      $ zip A_equal_timestamp_java_class.jar A.java A.class
      $ zip A_equal_timestamp_class_java.jar A.class A.java
      $ touch -t 03210320 A.java
      $ zip A_class_newer_java_class.jar A.java A.class
      $ zip A_class_newer_class_java.jar A.class A.java
      $ touch -t 03210322 A.java
      $ zip A_java_newer_java_class.jar A.java A.class
      $ zip A_java_newer_class_java.jar A.class A.java
      $ rm A.class
      $ echo 'public class B { static final String S = A.S; } ' > B.java
      $ mkdir build
      ```

      With JDK 8:
      ```
      $ rm -f build/* && javac -cp A_equal_timestamp_java_class.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_equal_timestamp_class_java.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_class_newer_java_class.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_class_newer_class_java.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_java_newer_java_class.jar -d build/ B.java
      $ ls build/
      A.class B.class
      $ rm -f build/* && javac -cp A_java_newer_class_java.jar -d build/ B.java
      ls build/
      A.class B.class
      ```

      For JDK 8, if the `.class` file is newer, it will be used and if the `.java` file is newer it will be used and compiled. If both `.class` and `.java` file have the same time stamp, JDK 8 chooses the `.class` file.

      With JDK 9+:
      ```
      $ rm -f build/* && javac -cp A_equal_timestamp_java_class.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_equal_timestamp_class_java.jar -d build/ B.java
      $ ls build/
      A.class B.class
      $ rm -f build/* && javac -cp A_class_newer_java_class.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_class_newer_class_java.jar -d build/ B.java
      $ ls build/
      B.class
      $ rm -f build/* && javac -cp A_java_newer_java_class.jar -d build/ B.java
      $ ls build/
      A.class B.class
      $ rm -f build/* && javac -cp A_java_newer_class_java.jar -d build/ B.java
      $ ls build/
      A.class B.class
      ```

      For JDK 9+, the cases where either one of the `.class` or `.java` file is newer are handled fine (and in the same way like in JDK 8). But if both `.class` and `.java` file have the same time stamp than it depends on their relative positon in the `.jar` file whether the `.class` file will be chosen or the `.java` file will be chosen and compiled into the output directory.

            Unassigned Unassigned
            simonis Volker Simonis
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: