Closed
Description
Env
$ openjdk 21-ea 2023-09-19
OpenJDK Runtime Environment (build 21-ea+20-1677)
OpenJDK 64-Bit Server VM (build 21-ea+20-1677, mixed mode, sharing)
google-javaformat = "1.17.0"
Error
> Task :spotlessJava FAILED
Step 'google-java-format' found problem in 'src/main/java/xxx/DOP.java':
57:10: error: java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.tree.JCTree.getStartPosition()" because "node" is null
at com.google.googlejavaformat.java.JavaInputAstVisitor.sync(JavaInputAstVisitor.java:3933)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitToDeclare(JavaInputAstVisitor.java:2799)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitEnhancedForLoop(JavaInputAstVisitor.java:791)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitEnhancedForLoop(JavaInputAstVisitor.java:167)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCEnhancedForLoop.accept(JCTree.java:1248)
at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
at com.google.googlejavaformat.java.JavaInputAstVisitor.scan(JavaInputAstVisitor.java:357)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitStatements(JavaInputAstVisitor.java:2229)
at com.google.googlejavaformat.java.JavaInputAstVisitor.methodBody(JavaInputAstVisitor.java:1550)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitMethod(JavaInputAstVisitor.java:1537)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitMethod(JavaInputAstVisitor.java:167)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:944)
at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
at com.google.googlejavaformat.java.JavaInputAstVisitor.scan(JavaInputAstVisitor.java:357)
at com.google.googlejavaformat.java.JavaInputAstVisitor.addBodyDeclarations(JavaInputAstVisitor.java:3760)
at com.google.googlejavaformat.java.JavaInputAstVisitor.visitClassDeclaration(JavaInputAstVisitor.java:2044)
at com.google.googlejavaformat.java.java17.Java17InputAstVisitor.visitClass(Java17InputAstVisitor.java:120)
at com.google.googlejavaformat.java.java17.Java17InputAstVisitor.visitClass(Java17InputAstVisitor.java:51)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:851)
at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
at com.google.googlejavaformat.java.JavaInputAstVisitor.scan(JavaInputAstVisitor.java:357)
I am not sure for which part it's failing. I was playing the java 21 preview features. So here is the sample file used in the task
Sample
import org.jspecify.annotations.NullMarked;
import java.io.*;
import java.lang.reflect.RecordComponent;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static java.lang.System.out;
import static java.util.Objects.requireNonNull;
public class DOP {
public static void main(String[] args) throws Exception {
run();
}
public static void run() throws Exception {
@NullMarked
record Person(String name, int age) {
}
var future = new CompletableFuture<>();
var textBlock = """
This is text block
This will join \
with the line : %s
"quote" = "added"
Escape Start \n \t \r \b \f end
Space Escape-\s\s\s\s\s\s\s\s\s\s-end
Regex \\S \\d \\D \\w \\W
\\d+
Escape char: \u0020 \u00A0 \u2000 \u3000 \uFEFF \u200B \u200C \u200D \u2028 \u2029
END
"""
.formatted(new Person("Foo", 40));
future.complete(textBlock);
out.println(future.get());
amberReflections();
recordPatterns();
genericRecordPattern();
serializeRecord();
}
private static void recordPatterns() {
record Point(int x, int y) {
}
var points = List.of(new Point(1, 2), new Point(3, 4), new Point(5, 6));
// Record pattern in enhanced for loop
for (Point(var x, var y) : points) {
out.println("Point: (" + x + ", " + y + ")");
}
}
interface Name<T> {
}
record FullName<T>(T firstName, T lastName) implements Name<T> {
}
private static void print(Name name) {
var result = switch (name) {
case FullName(var first, var last) -> first + ", " + last;
default -> "Invalid name";
};
out.println(result);
if (name instanceof FullName<?> f) {
// out.println(f.firstName() + ", " + f.lastName());
}
// Named record pattern is not supported
if (name instanceof FullName(var first, var last)) {
// out.println(first + ", " + last);
}
}
private static void genericRecordPattern() {
print(new FullName<>("Foo", "Bar"));
print(new FullName<>(1, 2));
print(new FullName<>(10L, 20L));
}
private static void amberReflections() {
var sealedClazz = Result.class;
out.println("Result (Interface) -> " + sealedClazz.isInterface());
out.println("Result (Sealed Class) -> " + sealedClazz.isSealed());
for (Class<?> permittedSubclass : sealedClazz.getPermittedSubclasses()) {
out.println("\nPermitted Subclass : " + permittedSubclass.getName());
if (permittedSubclass.isRecord()) {
out.println(permittedSubclass.getSimpleName() + " record components are,");
for (RecordComponent rc : permittedSubclass.getRecordComponents()) {
out.println(rc);
}
}
}
}
private static void serializeRecord() throws Exception {
// Local record
record Lang(String name, int year) implements Serializable {
Lang {
requireNonNull(name);
if (year <= 0) {
throw new IllegalArgumentException("Invalid year " + year);
}
}
}
var serialFile = Files.createTempFile("record-serial", "data").toFile();
serialFile.deleteOnExit();
try (var oos = new ObjectOutputStream(new FileOutputStream(serialFile))) {
List<Record> recs = List.of(
new Lang("Java", 25),
new Lang("Kotlin", 10),
(Record) Result.success(100)
);
for (Record rec : recs) {
out.println("Serializing record: " + rec);
oos.writeObject(rec);
}
oos.writeObject(null); // EOF
}
try (var ois = new ObjectInputStream(new FileInputStream(serialFile))) {
Object rec;
while ((rec = ois.readObject()) != null) {
var result = switch (rec) {
case null -> "n/a";
case Lang l when l.year >= 20 -> l.toString();
case Lang(var name, var year) -> name;
case Result<?> r -> "Result value: " + r.getOrNull();
default -> "Invalid serialized data. Expected Result, but found " + rec;
};
out.println("Deserialized record: " + rec);
out.println(result);
}
}
results().forEach(r -> {
var result = switch (r) {
case null -> "n/a";
case Result.Success<?> s -> s.toString();
case Result.Failure<?> f -> f.toString();
};
out.println("Result (Sealed Type): " + result);
});
}
static List<Result<?>> results() {
return Arrays.asList(getResult(5), getResult(25), getResult(-1));
}
static Result<Number> getResult(long l) {
// Unnecessary boxing required for boolean check in switch expression
return switch (Long.valueOf(l)) {
case Long s when s > 0 && s < 10 -> Result.success(s);
case Long s when s > 10 -> Result.failure(new IllegalArgumentException(String.valueOf(s)));
default -> null;
};
}
}