diff --git a/CHANGES.md b/CHANGES.md index 9ddcbdd86e..b0513de83f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ You might be looking for: * Updated default ktlint from 0.6.1 to 0.14.0 * Updated default google-java-format from 1.3 to 1.5 * Updated default eclipse-jdt from 4.7.1 to 4.7.2 +* Added a configuration option to `googleJavaFormat` to switch the formatter style ([#193](https://github.com/diffplug/spotless/pull/193)) ### Version 1.8.0 - January 2nd 2018 (javadoc [lib](https://diffplug.github.io/spotless/javadoc/spotless-lib/1.8.0/) [lib-extra](https://diffplug.github.io/spotless/javadoc/spotless-lib-extra/1.8.0/), artifact [lib]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib), [lib-extra]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib-extra))) diff --git a/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java b/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java index e83f1c09b4..2379711617 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java @@ -32,11 +32,19 @@ public class GoogleJavaFormatStep { private GoogleJavaFormatStep() {} private static final String DEFAULT_VERSION = "1.5"; + private static final String DEFAULT_STYLE = "GOOGLE"; static final String NAME = "google-java-format"; static final String MAVEN_COORDINATE = "com.google.googlejavaformat:google-java-format:"; static final String FORMATTER_CLASS = "com.google.googlejavaformat.java.Formatter"; static final String FORMATTER_METHOD = "formatSource"; + private static final String OPTIONS_CLASS = "com.google.googlejavaformat.java.JavaFormatterOptions"; + private static final String OPTIONS_BUILDER_METHOD = "builder"; + private static final String OPTIONS_BUILDER_CLASS = "com.google.googlejavaformat.java.JavaFormatterOptions$Builder"; + private static final String OPTIONS_BUILDER_STYLE_METHOD = "style"; + private static final String OPTIONS_BUILDER_BUILD_METHOD = "build"; + private static final String OPTIONS_Style = "com.google.googlejavaformat.java.JavaFormatterOptions$Style"; + private static final String REMOVE_UNUSED_CLASS = "com.google.googlejavaformat.java.RemoveUnusedImports"; private static final String REMOVE_UNUSED_METHOD = "removeUnusedImports"; @@ -53,10 +61,16 @@ public static FormatterStep create(Provisioner provisioner) { /** Creates a step which formats everything - code, import order, and unused imports. */ public static FormatterStep create(String version, Provisioner provisioner) { + return create(version, DEFAULT_STYLE, provisioner); + } + + /** Creates a step which formats everything - code, import order, and unused imports. */ + public static FormatterStep create(String version, String style, Provisioner provisioner) { Objects.requireNonNull(version, "version"); + Objects.requireNonNull(style, "style"); Objects.requireNonNull(provisioner, "provisioner"); return FormatterStep.createLazy(NAME, - () -> new State(NAME, version, provisioner), + () -> new State(NAME, version, style, provisioner), State::createFormat); } @@ -64,6 +78,10 @@ public static String defaultVersion() { return DEFAULT_VERSION; } + public static String defaultStyle() { + return DEFAULT_STYLE; + } + static final class State implements Serializable { private static final long serialVersionUID = 1L; @@ -71,11 +89,17 @@ static final class State implements Serializable { final JarState jarState; final String stepName; final String version; + final String style; State(String stepName, String version, Provisioner provisioner) throws IOException { + this(stepName, version, DEFAULT_STYLE, provisioner); + } + + State(String stepName, String version, String style, Provisioner provisioner) throws IOException { this.jarState = JarState.from(MAVEN_COORDINATE + version, provisioner); this.stepName = stepName; this.version = version; + this.style = style; } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -83,8 +107,21 @@ FormatterFunc createFormat() throws Exception { ClassLoader classLoader = jarState.getClassLoader(); // instantiate the formatter and get its format method + Class optionsClass = classLoader.loadClass(OPTIONS_CLASS); + Class optionsBuilderClass = classLoader.loadClass(OPTIONS_BUILDER_CLASS); + Method optionsBuilderMethod = optionsClass.getMethod(OPTIONS_BUILDER_METHOD); + Object optionsBuilder = optionsBuilderMethod.invoke(null); + + Class optionsStyleClass = classLoader.loadClass(OPTIONS_Style); + Object styleConstant = Enum.valueOf((Class) optionsStyleClass, style); + Method optionsBuilderStyleMethod = optionsBuilderClass.getMethod(OPTIONS_BUILDER_STYLE_METHOD, optionsStyleClass); + optionsBuilderStyleMethod.invoke(optionsBuilder, styleConstant); + + Method optionsBuilderBuildMethod = optionsBuilderClass.getMethod(OPTIONS_BUILDER_BUILD_METHOD); + Object options = optionsBuilderBuildMethod.invoke(optionsBuilder); + Class formatterClazz = classLoader.loadClass(FORMATTER_CLASS); - Object formatter = formatterClazz.getConstructor().newInstance(); + Object formatter = formatterClazz.getConstructor(optionsClass).newInstance(options); Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, String.class); Class removeUnusedClass = classLoader.loadClass(REMOVE_UNUSED_CLASS); diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index e79b901ff1..08e0cb09a2 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,6 +5,8 @@ * Updated default ktlint from 0.6.1 to 0.14.0 * Updated default google-java-format from 1.3 to 1.5 * Updated default eclipse-jdt from 4.7.1 to 4.7.2 +* Added a configuration option to `googleJavaFormat` to switch the formatter style ([#193](https://github.com/diffplug/spotless/pull/193)) + + Use `googleJavaFormat().aosp()` to use AOSP-compliant style (4-space indentation) instead of the default Google Style ### Version 3.8.0 - January 2nd 2018 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-plugin-gradle/3.8.0/), [jcenter](https://bintray.com/diffplug/opensource/spotless-plugin-gradle/3.8.0)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index cd21e6a2ca..9178dc2993 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -147,7 +147,9 @@ spotless { ```gradle spotless { java { - googleJavaFormat() // googleJavaFormat('1.1') to specify a specific version + googleJavaFormat() + // optional: you can specify a specific version and/or switch to AOSP style + googleJavaFormat('1.1').aosp() // you can then layer other format steps, such as licenseHeaderFile 'spotless.license.java' } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index ac828a9779..8d553bdaab 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -100,8 +100,8 @@ public void removeUnusedImports() { } /** Uses the [google-java-format](https://github.com/google/google-java-format) jar to format source code. */ - public void googleJavaFormat() { - googleJavaFormat(GoogleJavaFormatStep.defaultVersion()); + public GoogleJavaFormatConfig googleJavaFormat() { + return googleJavaFormat(GoogleJavaFormatStep.defaultVersion()); } /** @@ -110,9 +110,36 @@ public void googleJavaFormat() { * Limited to published versions. See [issue #33](https://github.com/diffplug/spotless/issues/33#issuecomment-252315095) * for an workaround for using snapshot versions. */ - public void googleJavaFormat(String version) { + public GoogleJavaFormatConfig googleJavaFormat(String version) { Objects.requireNonNull(version); - addStep(GoogleJavaFormatStep.create(version, GradleProvisioner.fromProject(getProject()))); + return new GoogleJavaFormatConfig(version); + } + + public class GoogleJavaFormatConfig { + final String version; + String style; + + GoogleJavaFormatConfig(String version) { + this.version = Objects.requireNonNull(version); + this.style = GoogleJavaFormatStep.defaultStyle(); + addStep(createStep()); + } + + public void style(String style) { + this.style = Objects.requireNonNull(style); + replaceStep(createStep()); + } + + public void aosp() { + style("AOSP"); + } + + private FormatterStep createStep() { + Project project = getProject(); + return GoogleJavaFormatStep.create(version, + style, + GradleProvisioner.fromProject(project)); + } } public EclipseConfig eclipse() { diff --git a/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java index a42dad1af9..b805a5d570 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java @@ -36,10 +36,21 @@ public void behavior() throws Exception { .testResource("java/googlejavaformat/JavaCodeWithPackageUnformatted.test", "java/googlejavaformat/JavaCodeWithPackageFormatted.test"); } + @Test + public void behaviorWithAospStyle() throws Exception { + FormatterStep step = GoogleJavaFormatStep.create("1.2", "AOSP", TestProvisioner.mavenCentral()); + StepHarness.forStep(step) + .testResource("java/googlejavaformat/JavaCodeUnformatted.test", "java/googlejavaformat/JavaCodeFormattedAOSP.test") + .testResource("java/googlejavaformat/JavaCodeWithLicenseUnformatted.test", "java/googlejavaformat/JavaCodeWithLicenseFormattedAOSP.test") + .testResource("java/googlejavaformat/JavaCodeWithLicensePackageUnformatted.test", "java/googlejavaformat/JavaCodeWithLicensePackageFormattedAOSP.test") + .testResource("java/googlejavaformat/JavaCodeWithPackageUnformatted.test", "java/googlejavaformat/JavaCodeWithPackageFormattedAOSP.test"); + } + @Test public void equality() throws Exception { new SerializableEqualityTester() { String version = "1.2"; + String style = ""; @Override protected void setupTest(API api) { @@ -48,12 +59,15 @@ protected void setupTest(API api) { // change the version, and it's different version = "1.1"; api.areDifferentThan(); + // change the style, and it's different + style = "AOSP"; + api.areDifferentThan(); } @Override protected FormatterStep create() { String finalVersion = this.version; - return GoogleJavaFormatStep.create(finalVersion, TestProvisioner.mavenCentral()); + return GoogleJavaFormatStep.create(finalVersion, style, TestProvisioner.mavenCentral()); } }.testEquals(); } diff --git a/testlib/src/test/resources/java/googlejavaformat/JavaCodeFormattedAOSP.test b/testlib/src/test/resources/java/googlejavaformat/JavaCodeFormattedAOSP.test new file mode 100644 index 0000000000..10ef7c35f9 --- /dev/null +++ b/testlib/src/test/resources/java/googlejavaformat/JavaCodeFormattedAOSP.test @@ -0,0 +1,11 @@ + +import mylib.UsedA; +import mylib.UsedB; + +public class Java { + public static void main(String[] args) { + System.out.println("hello"); + UsedB.someMethod(); + UsedA.someMethod(); + } +} diff --git a/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicenseFormattedAOSP.test b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicenseFormattedAOSP.test new file mode 100644 index 0000000000..4511380920 --- /dev/null +++ b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicenseFormattedAOSP.test @@ -0,0 +1,15 @@ +/* + * Some license stuff. + * Very official. + */ + +import mylib.UsedA; +import mylib.UsedB; + +public class Java { + public static void main(String[] args) { + System.out.println("hello"); + UsedB.someMethod(); + UsedA.someMethod(); + } +} diff --git a/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicensePackageFormattedAOSP.test b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicensePackageFormattedAOSP.test new file mode 100644 index 0000000000..a7b9693bfe --- /dev/null +++ b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithLicensePackageFormattedAOSP.test @@ -0,0 +1,12 @@ +package hello.world; + +import mylib.UsedA; +import mylib.UsedB; + +public class Java { + public static void main(String[] args) { + System.out.println("hello"); + UsedB.someMethod(); + UsedA.someMethod(); + } +} diff --git a/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithPackageFormattedAOSP.test b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithPackageFormattedAOSP.test new file mode 100644 index 0000000000..a7b9693bfe --- /dev/null +++ b/testlib/src/test/resources/java/googlejavaformat/JavaCodeWithPackageFormattedAOSP.test @@ -0,0 +1,12 @@ +package hello.world; + +import mylib.UsedA; +import mylib.UsedB; + +public class Java { + public static void main(String[] args) { + System.out.println("hello"); + UsedB.someMethod(); + UsedA.someMethod(); + } +}