ADDITIONAL SYSTEM INFORMATION :
JDK: Temurin 20.0.2+9
Edition Windows 10 Pro
Version 22H2
OS build 19045.3448
Experience Windows Feature Experience Pack 1000.19044.1000.0
A DESCRIPTION OF THE PROBLEM :
Depending on the order that you give the files to the compiler, the error for an "invalid permits clause" (where a child of a sealed class does not actually extend that class) is either given in the correct location, or an incorrect arbitrary location (I have seen it given in the middle of a comment in a totally separate class). I do not believe that the file ordering should matter, and even if it did, this is surely still an incorrect behaviour.
The source code given below reproduces the behaviour every time on the latest JDK.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the source code below, using Java 20.0.2+9 (also seen on Java 17). No external libraries are needed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected that in both compilations performed in the source code, the error should be indicated at the same place (the "BadChild" token on line 2 of Parent.java).
ACTUAL -
In the second case (the "bug order"), it indicates the error on line 4 of GoodChild.java.
---------- BEGIN SOURCE ----------
package org.example;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.stream.Collectors;
public class Main
{
public static void main(String[] args) throws IOException
{
File dir = Files.createTempDirectory("sealed-error-bug").toFile();
File parent = new File(dir, "Parent.java");
Files.write(parent.toPath(), """
// Parent is sealed and indicates two sub classes
sealed class Parent permits GoodChild, BadChild
{
}
""".lines().collect(Collectors.toList()));
File goodChild = new File(dir, "GoodChild.java");
Files.write(goodChild.toPath(), """
// GoodChild extends the sealed parent
final class GoodChild extends Parent
{
}
""".lines().collect(Collectors.toList()));
File badChild = new File(dir, "BadChild.java");
Files.write(badChild.toPath(), """
// BadChild does not extend the sealed parent
final class BadChild
{
}
""".lines().collect(Collectors.toList()));
DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>()
{
@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic)
{
System.out.println(diagnostic);
}
};
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, StandardCharsets.UTF_8);
sjfm.setLocation(StandardLocation.SOURCE_PATH, List.of(dir));
sjfm.setLocation(StandardLocation.CLASS_PATH, List.of(dir));
sjfm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(dir));
Iterable<? extends JavaFileObject> goodOrderOfInputs =
sjfm.getJavaFileObjectsFromFiles(List.of(parent, goodChild, badChild));
System.out.println("Compiling with fine order...");
jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, goodOrderOfInputs).call();
Iterable<? extends JavaFileObject> badOrderOfInputs =
sjfm.getJavaFileObjectsFromFiles(List.of(goodChild, badChild, parent));
System.out.println("Compiling with bug order...");
jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, badOrderOfInputs).call();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Pass the files in the right order, although it is not clear how to determine what the right order should be in all cases.
FREQUENCY : always
JDK: Temurin 20.0.2+9
Edition Windows 10 Pro
Version 22H2
OS build 19045.3448
Experience Windows Feature Experience Pack 1000.19044.1000.0
A DESCRIPTION OF THE PROBLEM :
Depending on the order that you give the files to the compiler, the error for an "invalid permits clause" (where a child of a sealed class does not actually extend that class) is either given in the correct location, or an incorrect arbitrary location (I have seen it given in the middle of a comment in a totally separate class). I do not believe that the file ordering should matter, and even if it did, this is surely still an incorrect behaviour.
The source code given below reproduces the behaviour every time on the latest JDK.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the source code below, using Java 20.0.2+9 (also seen on Java 17). No external libraries are needed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected that in both compilations performed in the source code, the error should be indicated at the same place (the "BadChild" token on line 2 of Parent.java).
ACTUAL -
In the second case (the "bug order"), it indicates the error on line 4 of GoodChild.java.
---------- BEGIN SOURCE ----------
package org.example;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.stream.Collectors;
public class Main
{
public static void main(String[] args) throws IOException
{
File dir = Files.createTempDirectory("sealed-error-bug").toFile();
File parent = new File(dir, "Parent.java");
Files.write(parent.toPath(), """
// Parent is sealed and indicates two sub classes
sealed class Parent permits GoodChild, BadChild
{
}
""".lines().collect(Collectors.toList()));
File goodChild = new File(dir, "GoodChild.java");
Files.write(goodChild.toPath(), """
// GoodChild extends the sealed parent
final class GoodChild extends Parent
{
}
""".lines().collect(Collectors.toList()));
File badChild = new File(dir, "BadChild.java");
Files.write(badChild.toPath(), """
// BadChild does not extend the sealed parent
final class BadChild
{
}
""".lines().collect(Collectors.toList()));
DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>()
{
@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic)
{
System.out.println(diagnostic);
}
};
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, StandardCharsets.UTF_8);
sjfm.setLocation(StandardLocation.SOURCE_PATH, List.of(dir));
sjfm.setLocation(StandardLocation.CLASS_PATH, List.of(dir));
sjfm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(dir));
Iterable<? extends JavaFileObject> goodOrderOfInputs =
sjfm.getJavaFileObjectsFromFiles(List.of(parent, goodChild, badChild));
System.out.println("Compiling with fine order...");
jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, goodOrderOfInputs).call();
Iterable<? extends JavaFileObject> badOrderOfInputs =
sjfm.getJavaFileObjectsFromFiles(List.of(goodChild, badChild, parent));
System.out.println("Compiling with bug order...");
jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, badOrderOfInputs).call();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Pass the files in the right order, although it is not clear how to determine what the right order should be in all cases.
FREQUENCY : always