-
Notifications
You must be signed in to change notification settings - Fork 0
Java code style
We use Google Style conventions with 4 spaces (instead of 2) for indentation. Other extensions and changes are described below.
Table of contents
- Javadocs
- Wrapping
- Static import for String.format()
- Dealing with nulls
- Returning immutable collections
- API for tests
- Suppress unchecked warnings using annotation
- Comment separators for sections of the class
- Formatting
Stringliteral
See Javadoc page for details.
When wrapped, the ternary operator should have ? and : starting lines with options. This way they look like a bulleted list:
EntityStorageRecord singleResult = shouldApplyFieldMask
? standStorage.read(singleId, fieldMask)
: standStorage.read(singleId);Place the newBuilder() call on a new line after the type:
CompositeColumnFilter result = CompositeColumnFilter
.newBuilder()
.addAllFilter(filters)
.setOperator(operator)
.build();This way in Java 11 we'd have a shorter construct with a type clearly visible on the same line:
var result = CompositeColumnFilter
.newBuilder()
...
.build();Use the following syntax for building formatted strings:
import static java.lang.String.format;
...
final String msg = format("Missing event handler for event class %s", eventClass);This makes the code more compact, and we don't need to read the text String twice on a line.
This annotation must be set in package-info.java of all the framework packages.
Everything which is not annotated with @Nullable is not null by default.
If it is needed to pass null to some method in tests, use Tests.<T>nullRef() method to avoid warning suppressions.
Non-nullity of parameters should be checked in public and protected methods to catch incorrect use of the API as early as possible.
If a method accepts two or more parameters that cannot be null, we call Preconditions.checkNotNull() in the order of parameters. checkNotNull() must be statically imported:
protected void dispatch(Message message, CommandContext context) {
checkNotNull(message);
checkNotNull(context);
...
}By convention, checking nullity of a state should be done via checkNotNull(), not via checkState(). For example, a Product.Builder’s method build() should look like this:
...
public Product build() {
checkNotNull(this.name, "Product name must be set.");
checkNotNull(this.price, "Product price must be set.");
...
}If a method returns a collection, it must be immutable. Use those provided by Guava.
If you really need to call some non-public method in tests, add a method wrapper with the access modifier you need.
This method must:
- have
@VisibleForTestingannotation (this means that the method is only for tests); - have the same name as the method of interest +
forTestsuffix; - not perform any complex actions, just calling the needed method is the best;
- have a Javadoc stating that this method is provided only for testing, and what method does it wrap.
The example:
// This is a private method to wrap
private void apply(Iterable<? extends Message> messages, CommandContext commandContext) {
...
}
/**
* This method is provided <em>only</em> for the purpose of testing event appliers
* of an aggregate and must not be called from the production code.
*
* <p>Calls {@link #apply(Iterable, CommandContext)}.
*/
@VisibleForTesting
public final void applyForTest(Message message, CommandContext commandContext) {
// may perform some setup
init();
// may wrap the checked exception
try {
apply(singletonList(message), commandContext);
} catch (InvocationTargetException e) {
throw propagate(e);
}
}Our experience proved that it does more harm than good. Framework tests that still use it would be eventually migrated.
Suppress unchecked warnings via standardized @SuppressWarnings annotation only instead of IntelliJ IDEA-specific //noinspection suppression style. We want to keep code compliant with any tool, not just with IntelliJ IDEA.
Please do. Framework users and developers need to know the reason why a warning was suppressed.
Use such comment separators if you need to split a class into sections:
/*
* Test command handlers
************************/Such comments are not collapsed in the IDE, so you can collapse all code blocks in the class and still see the comment separators, which is quite convenient.
Typically, the comment separators are useful in big test classes. We recommend to perform some refactoring instead of splitting a big production class into sections.
When concatenating a long string, start each continuation line with a space character:
String text = "This is an important error message." +
" Here are some details regarding what happened." +
" See the documentation for more information.";It's easier to spot and understand as a continuation. Oftentimes, people miss a space character in concatenated messages. With the starting space, it happens less often.