Skip to content

Commit 57d0c0b

Browse files
committed
fix #1076: Add support for palantir-java-format
1 parent 01e4d9e commit 57d0c0b

File tree

22 files changed

+686
-4
lines changed

22 files changed

+686
-4
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This document is intended for Spotless developers.
1010
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).
1111

1212
## [Unreleased]
13+
TODO(ckozak)
1314

1415
## [2.21.2] - 2022-01-07
1516
### Fixed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ extra('cpp.EclipseFormatterStep') +'{{yes}} | {{yes}}
5858
extra('groovy.GrEclipseFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
5959
lib('java.GoogleJavaFormatStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
6060
lib('java.ImportOrderStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
61+
lib('java.PalantirJavaFormatStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
6162
lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
6263
extra('java.EclipseJdtFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
6364
lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
@@ -98,6 +99,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}}
9899
| [`groovy.GrEclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/groovy/GrEclipseFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
99100
| [`java.GoogleJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
100101
| [`java.ImportOrderStep`](lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
102+
| [`java.PalantirJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
101103
| [`java.RemoveUnusedImportsStep`](lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
102104
| [`java.EclipseJdtFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseJdtFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
103105
| [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright 2016-2022 DiffPlug
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.diffplug.spotless.java;
17+
18+
import java.io.Serializable;
19+
import java.lang.reflect.Method;
20+
import java.util.Objects;
21+
22+
import com.diffplug.spotless.*;
23+
import com.diffplug.spotless.ThrowingEx.Function;
24+
25+
/** Wraps up <a href="https://github.com/palantir/palantir-java-format">palantir-java-format</a> fork of
26+
* <a href="https://github.com/google/google-java-format">google-java-format</a> as a FormatterStep. */
27+
public class PalantirJavaFormatStep {
28+
// prevent direct instantiation
29+
private PalantirJavaFormatStep() {}
30+
31+
private static final String DEFAULT_STYLE = "PALANTIR";
32+
static final String NAME = "palantir-java-format";
33+
static final String MAVEN_COORDINATE = "com.palantir.javaformat:palantir-java-format";
34+
static final String FORMATTER_CLASS = "com.palantir.javaformat.java.Formatter";
35+
static final String FORMATTER_METHOD = "formatSource";
36+
37+
private static final String OPTIONS_CLASS = "com.palantir.javaformat.java.JavaFormatterOptions";
38+
private static final String OPTIONS_BUILDER_METHOD = "builder";
39+
private static final String OPTIONS_BUILDER_CLASS = "com.palantir.javaformat.java.JavaFormatterOptions$Builder";
40+
private static final String OPTIONS_BUILDER_STYLE_METHOD = "style";
41+
private static final String OPTIONS_BUILDER_BUILD_METHOD = "build";
42+
private static final String OPTIONS_Style = "com.palantir.javaformat.java.JavaFormatterOptions$Style";
43+
private static final String OPTIONS_MAX_LINE_LENGTH_METHOD = "maxLineLength";
44+
45+
private static final String REMOVE_UNUSED_CLASS = "com.palantir.javaformat.java.RemoveUnusedImports";
46+
private static final String REMOVE_UNUSED_METHOD = "removeUnusedImports";
47+
48+
private static final String IMPORT_ORDERER_CLASS = "com.palantir.javaformat.java.ImportOrderer";
49+
private static final String IMPORT_ORDERER_METHOD = "reorderImports";
50+
51+
/** Creates a step which formats everything - code, import order, and unused imports. */
52+
public static FormatterStep create(Provisioner provisioner) {
53+
return create(defaultVersion(), provisioner);
54+
}
55+
56+
/** Creates a step which formats everything - code, import order, and unused imports. */
57+
public static FormatterStep create(String version, Provisioner provisioner) {
58+
return create(version, DEFAULT_STYLE, provisioner);
59+
}
60+
61+
/** Creates a step which formats everything - code, import order, and unused imports. */
62+
public static FormatterStep create(String version, String style, Provisioner provisioner) {
63+
return create(MAVEN_COORDINATE, version, style, provisioner);
64+
}
65+
66+
/** Creates a step which formats everything - groupArtifact, code, import order, and unused imports. */
67+
public static FormatterStep create(String groupArtifact, String version, String style, Provisioner provisioner) {
68+
Objects.requireNonNull(groupArtifact, "groupArtifact");
69+
if (groupArtifact.chars().filter(ch -> ch == ':').count() != 1) {
70+
throw new IllegalArgumentException("groupArtifact must be in the form 'groupId:artifactId'");
71+
}
72+
Objects.requireNonNull(version, "version");
73+
Objects.requireNonNull(style, "style");
74+
Objects.requireNonNull(provisioner, "provisioner");
75+
return FormatterStep.createLazy(NAME,
76+
() -> new State(NAME, groupArtifact, version, style, provisioner),
77+
State::createFormat);
78+
}
79+
80+
static final Jvm.Support<String> JVM_SUPPORT = Jvm.<String> support(NAME).add(8, "1.1.0").add(11, "2.10.0");
81+
82+
public static String defaultGroupArtifact() {
83+
return MAVEN_COORDINATE;
84+
}
85+
86+
/** Get default formatter version */
87+
public static String defaultVersion() {
88+
return JVM_SUPPORT.getRecommendedFormatterVersion();
89+
}
90+
91+
public static String defaultStyle() {
92+
return DEFAULT_STYLE;
93+
}
94+
95+
static final class State implements Serializable {
96+
private static final long serialVersionUID = 1L;
97+
98+
/** The jar that contains the formatter. */
99+
final JarState jarState;
100+
final String stepName;
101+
final String version;
102+
final String style;
103+
104+
State(String stepName, String version, Provisioner provisioner) throws Exception {
105+
this(stepName, version, DEFAULT_STYLE, provisioner);
106+
}
107+
108+
State(String stepName, String version, String style, Provisioner provisioner) throws Exception {
109+
this(stepName, MAVEN_COORDINATE, version, style, provisioner);
110+
}
111+
112+
State(String stepName, String groupArtifact, String version, String style, Provisioner provisioner) throws Exception {
113+
JVM_SUPPORT.assertFormatterSupported(version);
114+
this.jarState = JarState.from(groupArtifact + ":" + version, provisioner);
115+
this.stepName = stepName;
116+
this.version = version;
117+
this.style = style;
118+
}
119+
120+
@SuppressWarnings({"unchecked", "rawtypes"})
121+
FormatterFunc createFormat() throws Exception {
122+
ClassLoader classLoader = jarState.getClassLoader();
123+
124+
// instantiate the formatter and get its format method
125+
Class<?> optionsClass = classLoader.loadClass(OPTIONS_CLASS);
126+
Class<?> optionsBuilderClass = classLoader.loadClass(OPTIONS_BUILDER_CLASS);
127+
Method optionsBuilderMethod = optionsClass.getMethod(OPTIONS_BUILDER_METHOD);
128+
Object optionsBuilder = optionsBuilderMethod.invoke(null);
129+
130+
Class<?> optionsStyleClass = classLoader.loadClass(OPTIONS_Style);
131+
Object styleConstant = Enum.valueOf((Class<Enum>) optionsStyleClass, style);
132+
Method optionsBuilderStyleMethod = optionsBuilderClass.getMethod(OPTIONS_BUILDER_STYLE_METHOD, optionsStyleClass);
133+
optionsBuilderStyleMethod.invoke(optionsBuilder, styleConstant);
134+
135+
Method optionsBuilderBuildMethod = optionsBuilderClass.getMethod(OPTIONS_BUILDER_BUILD_METHOD);
136+
Object options = optionsBuilderBuildMethod.invoke(optionsBuilder);
137+
138+
Class<?> formatterClazz = classLoader.loadClass(FORMATTER_CLASS);
139+
Object formatter = formatterClazz.getMethod("createFormatter", optionsClass).invoke(null, options);
140+
Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
141+
142+
Function<String, String> removeUnused = constructRemoveUnusedFunction(classLoader);
143+
144+
Class<?> importOrdererClass = classLoader.loadClass(IMPORT_ORDERER_CLASS);
145+
Method importOrdererMethod = importOrdererClass.getMethod(IMPORT_ORDERER_METHOD, String.class);
146+
147+
return JVM_SUPPORT.suggestLaterVersionOnError(version, (input -> {
148+
String formatted = (String) formatterMethod.invoke(formatter, input);
149+
String removedUnused = removeUnused.apply(formatted);
150+
String sortedImports = (String) importOrdererMethod.invoke(null, removedUnused);
151+
return sortedImports;
152+
}));
153+
}
154+
155+
FormatterFunc createRemoveUnusedImportsOnly() throws Exception {
156+
ClassLoader classLoader = jarState.getClassLoader();
157+
Function<String, String> removeUnused = constructRemoveUnusedFunction(classLoader);
158+
return JVM_SUPPORT.suggestLaterVersionOnError(version, removeUnused::apply);
159+
}
160+
161+
private static Function<String, String> constructRemoveUnusedFunction(ClassLoader classLoader)
162+
throws NoSuchMethodException, ClassNotFoundException {
163+
Class<?> removeUnusedClass = classLoader.loadClass(REMOVE_UNUSED_CLASS);
164+
Method removeUnusedMethod = removeUnusedClass.getMethod(REMOVE_UNUSED_METHOD, String.class);
165+
return (x) -> (String) removeUnusedMethod.invoke(null, x);
166+
}
167+
}
168+
}

plugin-gradle/README.md

+28-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui
5858
- [**Quickstart**](#quickstart)
5959
- [Requirements](#requirements)
6060
- **Languages**
61-
- [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier))
61+
- [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format))
6262
- [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
6363
- [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
6464
- [Scala](#scala) ([scalafmt](#scalafmt))
@@ -203,6 +203,33 @@ org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAME
203203
```
204204
This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834).
205205

206+
### palantir-java-format
207+
208+
[homepage](https://github.com/palantir/palantir-java-format). [changelog](https://github.com/palantir/palantir-java-format/releases).
209+
```gradle
210+
spotless {
211+
java {
212+
palantirJavaFormat()
213+
// optional: you can specify a specific version and/or switch to GOOGLE/AOSP style
214+
// and/or use custom group artifact (you probably don't need this)
215+
palantirJavaFormat('2.9.0').style("PALANTIR").groupArtifact('com.google.googlejavaformat:google-java-format')
216+
```
217+
218+
**⚠️ Note on using Palantir Java Format with Java 16+**
219+
220+
Using Java 16+ with Palantir Java Format [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) on the running JDK.
221+
These Flags can be provided using the `gradle.properties` file (See [documentation](https://docs.gradle.org/current/userguide/build_environment.html)).
222+
223+
For example the following file under `gradle.properties` will run maven with the required flags:
224+
```
225+
org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
226+
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
227+
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
228+
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
229+
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
230+
```
231+
This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834).
232+
206233
### eclipse jdt
207234

208235
[homepage](https://www.eclipse.org/downloads/packages/). [compatible versions](https://github.com/diffplug/spotless/tree/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_jdt_formatter). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below.

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java

+51-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2022 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import com.diffplug.spotless.generic.LicenseHeaderStep;
3535
import com.diffplug.spotless.java.GoogleJavaFormatStep;
3636
import com.diffplug.spotless.java.ImportOrderStep;
37+
import com.diffplug.spotless.java.PalantirJavaFormatStep;
3738
import com.diffplug.spotless.java.RemoveUnusedImportsStep;
3839

3940
public class JavaExtension extends FormatExtension implements HasBuiltinDelimiterForLicense {
@@ -175,6 +176,55 @@ private FormatterStep createStep() {
175176
}
176177
}
177178

179+
/** Uses the <a href="https://github.com/palantir/palantir-java-format">palantir-java-format</a> jar to format source code. */
180+
public PalantirJavaFormatConfig palantirJavaFormat() {
181+
return palantirJavaFormat(PalantirJavaFormatStep.defaultVersion());
182+
}
183+
184+
/**
185+
* Uses the given version of <a href="https://github.com/palantir/palantir-java-format">palantir-java-format</a> to format source code.
186+
*
187+
* Limited to published versions. See <a href="https://github.com/diffplug/spotless/issues/33#issuecomment-252315095">issue #33</a>
188+
* for an workaround for using snapshot versions.
189+
*/
190+
public PalantirJavaFormatConfig palantirJavaFormat(String version) {
191+
Objects.requireNonNull(version);
192+
return new PalantirJavaFormatConfig(version);
193+
}
194+
195+
public class PalantirJavaFormatConfig {
196+
final String version;
197+
String groupArtifact;
198+
String style;
199+
200+
PalantirJavaFormatConfig(String version) {
201+
this.version = Objects.requireNonNull(version);
202+
this.groupArtifact = PalantirJavaFormatStep.defaultGroupArtifact();
203+
this.style = PalantirJavaFormatStep.defaultStyle();
204+
addStep(createStep());
205+
}
206+
207+
public PalantirJavaFormatConfig groupArtifact(String groupArtifact) {
208+
this.groupArtifact = Objects.requireNonNull(groupArtifact);
209+
replaceStep(createStep());
210+
return this;
211+
}
212+
213+
public PalantirJavaFormatConfig style(String style) {
214+
this.style = Objects.requireNonNull(style);
215+
replaceStep(createStep());
216+
return this;
217+
}
218+
219+
private FormatterStep createStep() {
220+
return PalantirJavaFormatStep.create(
221+
groupArtifact,
222+
version,
223+
style,
224+
provisioner());
225+
}
226+
}
227+
178228
public EclipseConfig eclipse() {
179229
return new EclipseConfig(EclipseJdtFormatterStep.defaultVersion());
180230
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2022 DiffPlug
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.diffplug.gradle.spotless;
17+
18+
import java.io.IOException;
19+
20+
import org.junit.jupiter.api.Test;
21+
22+
class PalantirJavaFormatIntegrationTest extends GradleIntegrationHarness {
23+
@Test
24+
void integration() throws IOException {
25+
setFile("build.gradle").toLines(
26+
"plugins {",
27+
" id 'com.diffplug.spotless'",
28+
"}",
29+
"repositories { mavenCentral() }",
30+
"",
31+
"spotless {",
32+
" java {",
33+
" target file('test.java')",
34+
" palantirJavaFormat('1.1.0')",
35+
" }",
36+
"}");
37+
38+
setFile("test.java").toResource("java/palantirjavaformat/JavaCodeUnformatted.test");
39+
gradleRunner().withArguments("spotlessApply").build();
40+
assertFile("test.java").sameAsResource("java/palantirjavaformat/JavaCodeFormatted.test");
41+
42+
checkRunsThenUpToDate();
43+
replace("build.gradle",
44+
"palantirJavaFormat('1.1.0')",
45+
"palantirJavaFormat('2.10.0')");
46+
checkRunsThenUpToDate();
47+
}
48+
}

plugin-maven/README.md

+25-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ user@machine repo % mvn spotless:check
4747
- [Requirements](#requirements)
4848
- [Binding to maven phase](#binding-to-maven-phase)
4949
- **Languages**
50-
- [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier))
50+
- [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format))
5151
- [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
5252
- [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
5353
- [Scala](#scala) ([scalafmt](#scalafmt))
@@ -223,6 +223,30 @@ For example the following file under `.mvn/jvm.config` will run maven with the r
223223
```
224224
This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834).
225225

226+
### palantir-java-format
227+
228+
[homepage](https://github.com/palantir/palantir-java-format). [changelog](https://github.com/palantir/palantir-java-format/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.java).
229+
230+
```xml
231+
<palantirJavaFormat>
232+
<version>2.10.0</version> <!-- optional -->
233+
<style>PALANTIR</style> <!-- or AOSP/GOOGLE (optional) -->
234+
<!-- optional: custom group artifact (you probably don't need this) -->
235+
<groupArtifact>com.palantir.javaformat:palantir-java-format</groupArtifact>
236+
</palantirJavaFormat>
237+
```
238+
239+
**⚠️ Note on using Palantir Java Format with Java 16+**
240+
241+
Using Java 16+ with Palantir Java Format [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) on the running JDK.
242+
These Flags can be provided using `MAVEN_OPTS` environment variable or using the `./mvn/jvm.config` file (See [documentation](https://maven.apache.org/configure.html#mvn-jvm-config-file)).
243+
244+
For example the following file under `.mvn/jvm.config` will run maven with the required flags:
245+
```
246+
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
247+
```
248+
This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834).
249+
226250
### eclipse jdt
227251

228252
[homepage](https://www.eclipse.org/downloads/packages/). [compatible versions](https://github.com/diffplug/spotless/tree/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_jdt_formatter). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Eclipse.java). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below.

0 commit comments

Comments
 (0)