The OpenTripPlanner Java code style is revised in OTP v2.2. We use the
Prettier Java as is. Maven is set up to
run prettier-maven-plugin. A check is run in the CI build, which fails the build preventing
merging a PR if the code style is incorrect.
Additionally since OTP v2.9, we are using Checkstyle to check for code style issues with a Maven plugin. There is also a checkstyle plugin for IntelliJ IDEA which can be used to spot and fix issues. We also have an OpenRewrite Maven plugin available that can be used to automatically fix some of the issues that are pointed out by Checkstyle. Comparison of different tools we considered can be found in #6913.
Checkstyle can be configured to be in use in IntelliJ with a plugin. Additionally, we have configured it to run by default as part of our Maven build. We also have OpenRewrite configured in maven to fix some issues automatically, but it is not run by default as it takes a bit longer to run.
Checkstyle will check for code style issues in the Maven "validate" phase, which runs before the test, package, and install phases. So checkstyle will happen for example when you run:
% mvn testYou can manually run only the checkstyle with:
% mvn checkstyle:checkThe check is run by the CI server and will fail the build if the code has code style issues.
To skip Checkstyle, use the profile checkstyleSkip:
% mvn test -P checkstyleSkipOpenRewrite can be used to fix some of the checkstyle issues automatically. The following command runs OpenRewrite and Prettier, but not checkstyle:
% mvn rewrite:run prettier:write -P rewriteThere are two ways to format the code before checking it in. You may run a normal build with Maven; it takes a bit of time, but it reformats the entire codebase. Only code you have changed should be formatted, since the existing code is already formatted. The second way is to set up Prettier and run it manually or hook it into your IDE, so it runs every time a file is changed.
Prettier will automatically format all code in the Maven "validate" phase, which runs before the test, package, and install phases. So formatting will happen for example when you run:
% mvn testYou can manually run only the formatting process with:
% mvn prettier:writeTo skip the Prettier formating, use the profile prettierSkip:
% mvn test -P prettierSkipTo check for formatting errors, use the profile prettierCheck:
% mvn test -P prettierCheckThe check is run by the CI server and will fail the build if the code is incorrectly formatted.
You should use the Prettier Maven plugin to reformat the code or run Prettier with Node (faster).
Prettier does not format the doc and Markdown files, only Java code. So, for other files you
should use the project code style. It is automatically imported when you first open the project.
But, if you have set a custom code style in your settings (as we used until OTP v2.1), then you need
to change to the Project code style. Open the Preferences from the menu and select Editor >
Code Style. Then select Project in the _Scheme drop down.
You can run the Prettier Maven plugin as an external tool in IntelliJ. Set it up as an
External tool and assign a keyboard shortcut to the tool execution.
Name: Prettier Format Current File
Program: mvn
Arguments: prettier:write -Dprettier.inputGlobs=$FilePathRelativeToProjectRoot$
Working Directory: $ProjectFileDir$
Tip! Add an unused key shortcut to execute the external tool. Then you can use the old shortcut to format other file types.
You can also configure IntelliJ to run Prettier every time IntelliJ saves a Java file. But if you are editing the file at the same time, you will get a warning that the file in memory and the file on disk both changed, and asked to select one of them.
- In the menu, open Preferences... and select Plugins.
- Search for "File Watchers" in the Marketplace.
- Run Install.
You can run Prettier upon every file save in IntelliJ using the File Watchers plugin. There are several ways to set it up. Below is how to configure it using Maven to run the formatter. The Maven way works without any installation of other components but might be a bit slow. So you might want to install prettier-java in your shell and run it instead.
Name: Format files with Prettier
File Type: Java
Scope: Project Files
Program: mvn
Arguments: prettier:write -Dprettier.inputGlobs=$FilePathRelativeToProjectRoot$
Working Directory: $ProjectFileDir$
We do not have support for other IDEs at the moment. If you use another editor and make one, please feel free to share it.
Some of the classes in OTP have a lot of fields and methods. Keeping members sorted reduces merge conflicts. Adding fields and methods to the end of the list will cause merge conflicts more often than inserting methods and fields in an ordered list. Fields and methods can be sorted in "feature" sections or alphabetically, but stick to it and respect it when adding new methods and fields.
The provided formatter will group class members in this order:
- Getter and setter methods are kept together.
- Overridden methods are kept together.
- Dependent methods are sorted in breadth-first order.
- Members are sorted like this:
static finalfields (constants)staticfields (avoid)- Instance fields
- Static initializers
- Class initializers
- Constructors
staticfactory methodspublicmethods- Getter and setters
private/package methodsprivateenums (avoidpublic)- Interfaces
private staticclasses (avoidpublic)- Instance classes (avoid)
As a matter of policy, all new
methods, classes, and fields should include comments explaining what they are for and any other
pertinent information. For Java code, the comments should follow industry standards. It is best to
provide comments that explain not only what you did but also why you did it while providing some
context. Please avoid including trivial Javadoc or the empty Javadoc stubs added by IDEs, such as
@param annotations with no description.
- On methods:
- Side effects on instance state (is it a pure function)
- Contract of the method
- Input domain for which the logic is designed
- Range of outputs produced from valid inputs
- Is behavior undefined or will the method fail when conditions are not met?
- Are null values allowed as inputs?
- Will null values occur as outputs (and what do they mean)?
- Invariants that hold if the preconditions are met
- Concurrency
- Is the method thread-safe?
- Usage constraints for multi-threaded use
- On classes:
- Initialization and teardown process
- Can an instance be reused for multiple operations, or should it be discarded?
- Is it immutable, or should anything be treated as immutable?
- Is it a utility class of static methods that should not be instantiated?
- On methods:
- Method should be marked as
@Nullableif they can return null values. - Method parameters should be marked as
@Nullableif they can take null values.
- Method should be marked as
- On fields:
- Fields should be marked as
@Nullableif they are nullable.
- Fields should be marked as
Use of @Nonnull annotation is not allowed. It should be assumed methods/parameters/fields are
non-null if they are not marked as @Nullable. However, there are places where the @Nullable
annotation is missing even if it should have been used. Those can be updated to use the @Nullable
annotation.
