Skip to content

Commit 56b6eab

Browse files
committed
java21:reworks all the packaging
1 parent 1ed1148 commit 56b6eab

File tree

13 files changed

+969
-6
lines changed

13 files changed

+969
-6
lines changed

palantir-java-format/build.gradle

Lines changed: 112 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ tasks.withType(JavaCompile).configureEach {
4949
options.compilerArgs += jvmArgList
5050

5151
if (JavaVersion.current() < JavaVersion.VERSION_14) {
52-
excludes = ['**/Java14InputAstVisitor.java']
52+
excludes = ['**/Java14InputAstVisitor.java', '**/Java21InputAstVisitor.java']
5353
}
5454
}
5555

@@ -62,7 +62,7 @@ tasks.withType(Javadoc).configureEach {
6262
options.optionFiles << file('../gradle/javadoc.options')
6363

6464
if (JavaVersion.current() < JavaVersion.VERSION_14) {
65-
exclude '**/Java14InputAstVisitor.java'
65+
excludes = ['**/Java14InputAstVisitor.java', '**/Java21InputAstVisitor.java']
6666
}
6767
}
6868

@@ -77,15 +77,122 @@ tasks.named("test") {
7777
systemProperty 'junit.jupiter.execution.parallel.mode.default', 'concurrent'
7878
}
7979

80-
// necessary to compile Java14InputAstVisitor
81-
idea {
82-
module.languageLevel = new org.gradle.plugins.ide.idea.model.IdeaLanguageLevel(14)
80+
81+
def target21Compiler = javaToolchains.compilerFor {
82+
it.languageVersion = JavaLanguageVersion.of(21)
83+
}
84+
85+
def target21Launcher = javaToolchains.launcherFor {
86+
it.languageVersion = JavaLanguageVersion.of(21)
87+
}
88+
89+
90+
sourceSets.create("java21") {
91+
}
92+
93+
sourceSets.create("test21") {
94+
}
95+
96+
tasks.named("compileJava21Java", JavaCompile) {
97+
it.javaCompiler = target21Compiler
98+
it.sourceCompatibility = 21
99+
it.targetCompatibility = 21
100+
it.source = sourceSets.named("java21").get().java
101+
it.classpath = project.objects.fileCollection().from(
102+
sourceSets.named("main").get().output,
103+
sourceSets.named("main").get().compileClasspath,
104+
sourceSets.named("java21").get().compileClasspath
105+
)
106+
}
107+
108+
tasks.named("compileTest21Java", JavaCompile) {
109+
it.javaCompiler = target21Compiler
110+
it.sourceCompatibility = 21
111+
it.targetCompatibility = 21
112+
it.source = sourceSets.named("test21").get().java
113+
it.classpath = sourceSets.named("test").get().runtimeClasspath
114+
}
115+
116+
tasks.register("testJava21", Test) {
117+
118+
it.group = "verification"
119+
it.javaLauncher.set(target21Launcher.get())
120+
121+
useJUnitPlatform()
122+
123+
it.testClassesDirs = project.objects.fileCollection().from(
124+
sourceSets.named("test21").get().output.classesDirs
125+
)
126+
it.classpath = project.objects.fileCollection().from(
127+
sourceSets.named("test21").get().output,
128+
sourceSets.named("java21").get().output,
129+
sourceSets.named("test").get().runtimeClasspath
130+
)
131+
}
132+
133+
134+
sourceSets.create("java21Preview") {
135+
java.srcDirs(project.layout.projectDirectory.dir("src/java21Preview/java"))
136+
}
137+
138+
sourceSets.create("test21Preview") {
139+
java.srcDirs(project.layout.projectDirectory.dir("src/test21Preview/java"))
83140
}
84141

142+
tasks.named("compileJava21PreviewJava", JavaCompile) {
143+
it.javaCompiler = target21Compiler
144+
it.sourceCompatibility = 21
145+
it.targetCompatibility = 21
146+
options.compilerArgs += '--enable-preview'
147+
it.source = sourceSets.named("java21Preview").get().java
148+
it.classpath = objects.fileCollection().from(
149+
sourceSets.named("main").get().output,
150+
sourceSets.named("java21").get().output,
151+
sourceSets.named("main").get().compileClasspath,
152+
sourceSets.named("java21Preview").get().compileClasspath
153+
154+
)
155+
}
156+
157+
tasks.named("compileTest21PreviewJava", JavaCompile) {
158+
it.javaCompiler = target21Compiler
159+
it.sourceCompatibility = 21
160+
it.targetCompatibility = 21
161+
options.compilerArgs += '--enable-preview'
162+
it.source = sourceSets.named("test21Preview").get().java
163+
it.classpath = sourceSets.named("test").get().runtimeClasspath
164+
}
165+
166+
tasks.register("testJava21Preview", Test) {
167+
168+
it.group = "verification"
169+
it.javaLauncher.set(target21Launcher.get())
170+
jvmArgs += '--enable-preview'
171+
useJUnitPlatform()
172+
173+
it.testClassesDirs = project.objects.fileCollection().from(
174+
sourceSets.named("test21Preview").get().output.classesDirs
175+
)
176+
it.classpath = project.objects.fileCollection().from(
177+
sourceSets.named("test21Preview").get().output,
178+
sourceSets.named("java21Preview").get().output,
179+
sourceSets.named("java21").get().output,
180+
sourceSets.named("test").get().runtimeClasspath
181+
)
182+
}
183+
184+
tasks.check { dependsOn(test,testJava21,testJava21Preview) }
185+
85186
// This block may be replaced by BaselineExportsExtension exports
86187
// once https://github.com/gradle/gradle/issues/18824 is resolved.
87188
tasks.named("jar", Jar) {
88189
manifest {
89190
attributes('Add-Exports': exports.join(' '))
90191
}
192+
it.from(
193+
sourceSets.named("main").get().output,
194+
sourceSets.named("java21").get().output,
195+
sourceSets.named("java21Preview").get().output
196+
)
197+
91198
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.palantir.javaformat.java.java21;
18+
19+
import com.google.common.collect.Iterables;
20+
import com.palantir.javaformat.OpsBuilder;
21+
import com.palantir.javaformat.java.JavaInputAstVisitor;
22+
import com.palantir.javaformat.java.java14.Java14InputAstVisitor;
23+
import com.sun.source.tree.BlockTree;
24+
import com.sun.source.tree.CaseTree;
25+
import com.sun.source.tree.ConstantCaseLabelTree;
26+
import com.sun.source.tree.DeconstructionPatternTree;
27+
import com.sun.source.tree.ParenthesizedTree;
28+
import com.sun.source.tree.PatternCaseLabelTree;
29+
import com.sun.source.tree.PatternTree;
30+
import com.sun.source.tree.Tree;
31+
import com.sun.source.tree.Tree.Kind;
32+
import java.lang.reflect.Method;
33+
import java.util.List;
34+
35+
/**
36+
* Extends {@link Java14InputAstVisitor} with support for AST nodes that were added or modified for Java 14.
37+
*/
38+
public class Java21InputAstVisitor extends Java14InputAstVisitor {
39+
private static final Method CASE_TREE_GET_LABELS2 = maybeGetMethodPrivate(CaseTree.class, "getLabels");
40+
41+
private static Method maybeGetMethodPrivate(Class<?> c, String name) {
42+
try {
43+
return c.getMethod(name);
44+
} catch (ReflectiveOperationException e) {
45+
return null;
46+
}
47+
}
48+
49+
private static Object invokePrivate(Method m, Object target) {
50+
try {
51+
return m.invoke(target);
52+
} catch (ReflectiveOperationException e) {
53+
throw new RuntimeException(e.getMessage(), e);
54+
}
55+
}
56+
57+
public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
58+
super(builder, indentMultiplier);
59+
}
60+
61+
@Override
62+
public Void visitParenthesized(ParenthesizedTree node, Void unused) {
63+
token("(");
64+
Void v = scan(node.getExpression(), unused);
65+
token(")");
66+
return v;
67+
}
68+
69+
@Override
70+
public Void visitDeconstructionPattern(DeconstructionPatternTree node, Void unused) {
71+
72+
Void r = scan(node.getDeconstructor(), unused);
73+
token("(");
74+
boolean firstInRow = true;
75+
for (PatternTree item : node.getNestedPatterns()) {
76+
if (!firstInRow) {
77+
token(",");
78+
builder.breakToFill(" ");
79+
}
80+
scan(item, null);
81+
firstInRow = false;
82+
}
83+
token(")");
84+
return r;
85+
}
86+
87+
@Override
88+
public Void visitConstantCaseLabel(ConstantCaseLabelTree node, Void unused) {
89+
return scan(node.getConstantExpression(), unused);
90+
}
91+
92+
@Override
93+
public Void visitCase(CaseTree node, Void unused) {
94+
sync(node);
95+
markForPartialFormat();
96+
builder.forcedBreak();
97+
List<? extends Tree> labels;
98+
boolean isDefault;
99+
if (CASE_TREE_GET_LABELS2 != null) {
100+
labels = (List<? extends Tree>) invokePrivate(CASE_TREE_GET_LABELS2, node);
101+
isDefault = labels.size() == 1
102+
&& Iterables.getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL");
103+
} else {
104+
labels = node.getExpressions();
105+
isDefault = labels.isEmpty();
106+
}
107+
if (isDefault) {
108+
token("default", plusTwo);
109+
} else {
110+
token("case", plusTwo);
111+
builder.space();
112+
builder.open(labels.size() > 1 ? plusFour : JavaInputAstVisitor.ZERO);
113+
boolean first = true;
114+
for (Tree expression : labels) {
115+
if (!first) {
116+
token(",");
117+
builder.breakOp(" ");
118+
}
119+
scan(expression, null);
120+
first = false;
121+
}
122+
builder.close();
123+
}
124+
switch (node.getCaseKind()) {
125+
case STATEMENT:
126+
token(":");
127+
boolean isBlock = node.getStatements().size() == 1
128+
&& node.getStatements().get(0).getKind() == Kind.BLOCK;
129+
builder.open(isBlock ? JavaInputAstVisitor.ZERO : plusTwo);
130+
if (isBlock) {
131+
builder.space();
132+
}
133+
visitStatements(node.getStatements(), isBlock);
134+
builder.close();
135+
break;
136+
case RULE:
137+
if (node.getGuard() != null) {
138+
builder.space();
139+
token("when");
140+
builder.space();
141+
scan(node.getGuard(), null);
142+
}
143+
144+
builder.space();
145+
token("-");
146+
token(">");
147+
148+
builder.space();
149+
if (node.getBody().getKind() == Kind.BLOCK) {
150+
// Explicit call with {@link CollapseEmptyOrNot.YES} to handle empty case blocks.
151+
visitBlock(
152+
(BlockTree) node.getBody(),
153+
CollapseEmptyOrNot.YES,
154+
AllowLeadingBlankLine.NO,
155+
AllowTrailingBlankLine.NO);
156+
} else {
157+
scan(node.getBody(), null);
158+
}
159+
builder.guessToken(";");
160+
break;
161+
default:
162+
throw new IllegalArgumentException(node.getCaseKind().name());
163+
}
164+
return null;
165+
}
166+
167+
public Void visitPatternCaseLabel(PatternCaseLabelTree node, Void p) {
168+
return scan(node.getPattern(), p);
169+
}
170+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.palantir.javaformat.java.java21;
17+
18+
import com.palantir.javaformat.OpsBuilder;
19+
import com.sun.source.tree.AnyPatternTree;
20+
21+
public class Java21PreviewInputAstVisitor extends Java21InputAstVisitor {
22+
23+
public Java21PreviewInputAstVisitor(OpsBuilder builder, int indentMultiplier) {
24+
super(builder, indentMultiplier);
25+
}
26+
27+
public Void visitAnyPattern(AnyPatternTree node, Void p) {
28+
token("_");
29+
return p;
30+
}
31+
}

palantir-java-format/src/main/java/com/palantir/javaformat/java/Formatter.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.sun.tools.javac.util.Log;
4646
import com.sun.tools.javac.util.Options;
4747
import java.io.IOException;
48+
import java.lang.management.ManagementFactory;
4849
import java.net.URI;
4950
import java.util.Collection;
5051
import javax.tools.Diagnostic;
@@ -131,7 +132,26 @@ static JavaOutput format(
131132
OpsBuilder opsBuilder = new OpsBuilder(javaInput);
132133

133134
JavaInputAstVisitor visitor;
134-
if (getRuntimeVersion() >= 14) {
135+
136+
if (getRuntimeVersion() >= 21 && isEnabledPriew()) {
137+
try {
138+
visitor = Class.forName("com.palantir.javaformat.java.java21.Java21PreviewInputAstVisitor")
139+
.asSubclass(JavaInputAstVisitor.class)
140+
.getConstructor(OpsBuilder.class, int.class)
141+
.newInstance(opsBuilder, options.indentationMultiplier());
142+
} catch (ReflectiveOperationException e) {
143+
throw new RuntimeException(e.getMessage(), e);
144+
}
145+
} else if (getRuntimeVersion() >= 21) {
146+
try {
147+
visitor = Class.forName("com.palantir.javaformat.java.java21.Java21InputAstVisitor")
148+
.asSubclass(JavaInputAstVisitor.class)
149+
.getConstructor(OpsBuilder.class, int.class)
150+
.newInstance(opsBuilder, options.indentationMultiplier());
151+
} catch (ReflectiveOperationException e) {
152+
throw new RuntimeException(e.getMessage(), e);
153+
}
154+
} else if (getRuntimeVersion() >= 14) {
135155
try {
136156
visitor = Class.forName("com.palantir.javaformat.java.java14.Java14InputAstVisitor")
137157
.asSubclass(JavaInputAstVisitor.class)
@@ -206,6 +226,11 @@ static int getRuntimeVersion() {
206226
return Runtime.version().feature();
207227
}
208228

229+
@VisibleForTesting
230+
static boolean isEnabledPriew() {
231+
return ManagementFactory.getRuntimeMXBean().getInputArguments().contains("--enable-preview");
232+
}
233+
209234
static boolean errorDiagnostic(Diagnostic<?> input) {
210235
if (input.getKind() != Diagnostic.Kind.ERROR) {
211236
return false;

0 commit comments

Comments
 (0)