Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format Java source files automatically #46745

Merged
merged 22 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f6176bf
Format Java using google-java-format
pugnascotia Sep 16, 2019
e833d42
Add notes on handling file that do not format
pugnascotia Sep 16, 2019
72274ca
Apply format plugin in the right place
pugnascotia Sep 16, 2019
a5eec34
Some big examples of reformatted code
pugnascotia Sep 16, 2019
1194956
Switch to Spotless for code formatting
pugnascotia Sep 17, 2019
b5d2b34
Changes to make Spotless format consistently
pugnascotia Sep 18, 2019
d85a1d4
Only format projects on an accept list.
pugnascotia Sep 18, 2019
5ef0dc4
Revert formatted outside of buildSrc
pugnascotia Sep 18, 2019
06ab706
Format buildSrc directory
pugnascotia Sep 18, 2019
5c1ee6a
Merge remote-tracking branch 'upstream/master' into auto-format-java-…
pugnascotia Sep 18, 2019
6a32487
Reformat after merge
pugnascotia Sep 18, 2019
4423991
Update checkstyle suppressions
pugnascotia Sep 18, 2019
0c432a5
Add an option to enable paddedCell() from the gradle CLI
pugnascotia Sep 21, 2019
e1d27cd
Format java with with Eclipse JDT instead
pugnascotia Sep 21, 2019
b0d0d6d
Reformat buildSrc/
pugnascotia Sep 21, 2019
7d69c76
More formatter settings tweaks
pugnascotia Sep 23, 2019
8418c15
Revert formatted ahead of merge with master
pugnascotia Sep 25, 2019
82c44b7
Merge remote-tracking branch 'upstream/master' into auto-format-java-…
pugnascotia Sep 25, 2019
5b76280
Leave the formatting project list empty, so we can merge the Gradle c…
pugnascotia Sep 25, 2019
2a2856b
Update CONTRIBUTING.md
pugnascotia Sep 25, 2019
896cbe3
Update CONTRIBUTING.md
pugnascotia Sep 25, 2019
7314c3a
Remove spotless command that the formatter already handles
pugnascotia Sep 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
362 changes: 362 additions & 0 deletions .eclipseformat.xml

Large diffs are not rendered by default.

67 changes: 58 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,68 @@ For Eclipse, go to `Preferences->Java->Installed JREs` and add `-ea` to

### Java Language Formatting Guidelines

Java files in the Elasticsearch codebase are formatted with the Eclipse JDT
formatter, using the [Spotless
Gradle](https://github.com/diffplug/spotless/tree/master/plugin-gradle)
plugin. This plugin is configured on a project-by-project basis, via
`build.gradle` in the root of the repository. So long as at least one
project is configured, the formatting check can be run explicitly with:

./gradlew spotlessJavaCheck

The code can be formatted with:

./gradlew spotlessApply

These tasks can also be run for specific subprojects, e.g.

./gradlew server:spotlessJavaCheck

Please follow these formatting guidelines:

* Java indent is 4 spaces
* Line width is 140 characters
* Lines of code surrounded by `// tag` and `// end` comments are included in the
documentation and should only be 76 characters wide not counting
leading indentation
* The rest is left to Java coding standards
* Disable “auto-format on save” to prevent unnecessary format changes. This makes reviews much harder as it generates unnecessary formatting changes. If your IDE supports formatting only modified chunks that is fine to do.
* Wildcard imports (`import foo.bar.baz.*`) are forbidden and will cause the build to fail. This can be done automatically by your IDE:
* Eclipse: `Preferences->Java->Code Style->Organize Imports`. There are two boxes labeled "`Number of (static )? imports needed for .*`". Set their values to 99999 or some other absurdly high value.
* IntelliJ: `Preferences/Settings->Editor->Code Style->Java->Imports`. There are two configuration options: `Class count to use import with '*'` and `Names count to use static import with '*'`. Set their values to 99999 or some other absurdly high value.
* Don't worry too much about import order. Try not to change it but don't worry about fighting your IDE to stop it from doing so.
* Lines of code surrounded by `// tag` and `// end` comments are included
in the documentation and should only be 76 characters wide not counting
leading indentation
* Wildcard imports (`import foo.bar.baz.*`) are forbidden and will cause
the build to fail. This can be done automatically by your IDE:
* Eclipse: `Preferences->Java->Code Style->Organize Imports`. There are
two boxes labeled "`Number of (static )? imports needed for .*`". Set
their values to 99999 or some other absurdly high value.
* IntelliJ: `Preferences/Settings->Editor->Code Style->Java->Imports`.
There are two configuration options: `Class count to use import with
'*'` and `Names count to use static import with '*'`. Set their values
to 99999 or some other absurdly high value.

#### Editor / IDE Support

Eclipse IDEs can import the file [elasticsearch.eclipseformat.xml]
directly.

IntelliJ IDEs can
[import](https://blog.jetbrains.com/idea/2014/01/intellij-idea-13-importing-code-formatter-settings-from-eclipse/)
the same settings file, and / or use the [Eclipse Code
Formatter](https://plugins.jetbrains.com/plugin/6546-eclipse-code-formatter)
plugin.

You can also tell Spotless to [format a specific
file](https://github.com/diffplug/spotless/tree/master/plugin-gradle#can-i-apply-spotless-to-specific-files)
from the command line.

#### Formatting failures

Sometimes Spotless will report a "misbehaving rule which can't make up its
mind" and will recommend enabling the `paddedCell()` setting. If you
enabled this settings and run the format check again,
Spotless will write files to
`$PROJECT/build/spotless-diagnose-java/` to aid diagnosis. It writes
different copies of the formatted files, so that you can see how they
differ and infer what is the problem.

The `paddedCell() option is disabled for normal operation in order to
detect any misbehaviour. You can enabled the option from the command line
by running Gradle with `-Dspotless.paddedcell`.

### License Headers

Expand Down
29 changes: 29 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ plugins {
id 'com.gradle.build-scan' version '2.4'
id 'lifecycle-base'
id 'elasticsearch.global-build-info'
id "com.diffplug.gradle.spotless" version "3.24.2" apply false
}

apply plugin: 'nebula.info-scm'
Expand Down Expand Up @@ -98,6 +99,34 @@ subprojects {
plugins.withType(BuildPlugin).whenPluginAdded {
project.licenseFile = project.rootProject.file('licenses/APACHE-LICENSE-2.0.txt')
project.noticeFile = project.rootProject.file('NOTICE.txt')

// Projects that should be formatted and checked with Spotless are
// listed here, by project path. Once the number of formatted projects
// is greater than the number of unformatted projects, this can be
// switched to an exclude list, and eventualy removed completely.
def projectPathsToFormat = [
// ':build-tools'
]

if (projectPathsToFormat.contains(project.path)) {
project.apply plugin: "com.diffplug.gradle.spotless"

spotless {
java {

removeUnusedImports()
pugnascotia marked this conversation as resolved.
Show resolved Hide resolved
eclipse().configFile rootProject.file('.eclipseformat.xml')
trimTrailingWhitespace()

// See CONTRIBUTING.md for details of when to enabled this.
if (System.getProperty('spotless.paddedcell') != null) {
paddedCell()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we have everything about the formatting doable by the IDE plugins?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we'll have much need to enable this on a day-to-day basis, and it's outside the remit of the IDE plugins. This option lets Spotless cope when formatting isn't idempotent, which happened in a few places with GJF. It's a seperate thing from the configured formatting options.

}
}
}

precommit.dependsOn 'spotlessJavaCheck'
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ dependencies {
compile 'com.netflix.nebula:gradle-extra-configurations-plugin:3.0.3'
compile 'com.netflix.nebula:nebula-publishing-plugin:4.4.4'
compile 'com.netflix.nebula:gradle-info-plugin:3.0.3'
compile 'org.eclipse.jgit:org.eclipse.jgit:3.2.0.201312181205-r'
compile 'org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r'
compile 'com.perforce:p4java:2012.3.551082' // THIS IS SUPPOSED TO BE OPTIONAL IN THE FUTURE....
compile 'org.apache.rat:apache-rat:0.11'
compile "org.elasticsearch:jna:4.5.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ Constructor<?> compile(Loader loader, Set<String> extractedVariables, String nam
}

return clazz.getConstructors()[0];
} catch (Exception exception) { // Catch everything to let the user know this is something caused internally.
} catch (Exception exception) {
// Catch everything to let the user know this is something caused internally.
throw new IllegalStateException("An internal error occurred attempting to define the script [" + name + "].", exception);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,32 +60,35 @@
* {@link java.lang.invoke.LambdaMetafactory} since the Painless casting model
* cannot be fully supported through this class.
*
* For each lambda function/method reference used within a Painless script
* <p>For each lambda function/method reference used within a Painless script
* a class will be generated at link-time using the
* {@link LambdaBootstrap#lambdaBootstrap} method that contains the following:
* 1. member fields for any captured variables
* 2. a constructor that will take in captured variables and assign them to
*
* <ol>
* <li>member fields for any captured variables
* <li>a constructor that will take in captured variables and assign them to
* their respective member fields
* 3. a static ctor delegation method, if the lambda function is a ctor.
* 4. a method that will load the member fields representing captured variables
* <li>a static ctor delegation method, if the lambda function is a ctor.
* <li>a method that will load the member fields representing captured variables
* and take in any other necessary values based on the arguments passed into the
* lambda function/reference method; it will then make a delegated call to the
* actual lambda function/reference method
* actual lambda function/reference method.
* </ol>
*
* Take for example the following Painless script:
* <p>Take for example the following Painless script:
*
* {@code
* <pre>{@code
* List list1 = new ArrayList(); "
* list1.add(2); "
* List list2 = new ArrayList(); "
* list1.forEach(x -> list2.add(x));"
* return list[0]"
* }
* }</pre>
*
* The script contains a lambda function with a captured variable.
* <p>The script contains a lambda function with a captured variable.
* The following Lambda class would be generated:
*
* {@code
* <pre>{@code
* public static final class $$Lambda0 implements Consumer {
* private List arg$0;
*
Expand All @@ -109,9 +112,9 @@
* }
* ...
* }
* }
* }</pre>
*
* Also the accept method actually uses an invokedynamic
* <p>Also the accept method actually uses an invokedynamic
* instruction to call the lambda$0 method so that
* {@link MethodHandle#asType} can be used to do the necessary
* conversions between argument types without having to hard
Expand All @@ -120,7 +123,7 @@
* calls the constructor. This method is used by the
* invokedynamic call to initialize the instance.
*
* When the {@link CallSite} is linked the linked method depends
* <p>When the {@link CallSite} is linked the linked method depends
* on whether or not there are captures. If there are no captures
* the same instance of the generated lambda class will be
* returned each time by the factory method as there are no
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,8 @@ private <T> T generateFactory(Loader loader, ScriptContext<T> context, Set<Strin

try {
return context.factoryClazz.cast(factory.getConstructor().newInstance());
} catch (Exception exception) { // Catch everything to let the user know this is something caused internally.
} catch (Exception exception) {
// Catch everything to let the user know this is something caused internally.
throw new IllegalStateException(
"An internal error occurred attempting to define the factory class [" + className + "].", exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ void write(MethodWriter writer, Globals globals) {
// from dup the value onto the stack
}

lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
// store the lhs's value from the stack in its respective variable/field/array
lhs.store(writer, globals);
} else if (operation != null) {
// Handle the case where we are doing a compound assignment that
// does not represent a String concatenation.
Expand All @@ -309,9 +310,9 @@ void write(MethodWriter writer, Globals globals) {
// to the promotion type between the lhs and rhs types
rhs.write(writer, globals); // write the bytecode for the rhs

// XXX: fix these types, but first we need def compound assignment tests.
// its tricky here as there are possibly explicit casts, too.
// write the operation instruction for compound assignment
// XXX: fix these types, but first we need def compound assignment tests.
// its tricky here as there are possibly explicit casts, too.
// write the operation instruction for compound assignment
if (promote == def.class) {
writer.writeDynamicBinaryInstruction(
location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT);
Expand All @@ -322,23 +323,24 @@ void write(MethodWriter writer, Globals globals) {
writer.writeCast(back); // if necessary cast the promotion type value back to the lhs's type

if (lhs.read && !post) {
writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
// read from and is not a post
// increment
// dup the value if the lhs is also read from and is not a post increment
writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount());
}

lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
// store the lhs's value from the stack in its respective variable/field/array
lhs.store(writer, globals);
} else {
// Handle the case for a simple write.

rhs.write(writer, globals); // write the bytecode for the rhs rhs

if (lhs.read) {
writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs
// is also read from
// dup the value if the lhs is also read from
writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount());
}

lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
// store the lhs's value from the stack in its respective variable/field/array
lhs.store(writer, globals);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
* <p>
* Generally, expression nodes have member data that evaluate static and def types. The typical order for an expression node
* during the analysis phase looks like the following:
* {@code
* <pre>{@code
* For known expected types:
*
* expression.child.expected = expectedType // set the known expected type
Expand All @@ -132,7 +132,7 @@
* expression.child = expression.child.cast(...) // add an implicit cast node if the child node's
* // actual type is not the expected type and set the
* // expression's child to the implicit cast node
* }
* }</pre>
* Expression nodes just call each child during the writing phase.
* <p>
* Postfix nodes represent postfixes in a variable/method chain including braces, calls, or fields.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ private void expectOutOfBounds(int index, String script, Object val) {
*/
assertThat(e.getMessage(), outOfBoundsExceptionMessageMatcher(index, 5));
} catch (AssertionError ae) {
ae.addSuppressed(e); // Mark the exception we are testing as suppressed so we get its stack trace.
// Mark the exception we are testing as suppressed so we get its stack trace.
ae.addSuppressed(e);
throw ae;
}
}
Expand Down