|
|
[[_TOC_]]
|
|
|
|
|
|
## About
|
|
|
|
|
|
This document defines the Java coding standards for source files in the OSDU community. It is primarily intended for the OSDU contributor teams.
|
|
|
|
|
|
## Basis
|
|
|
|
|
|
This document is based on and mostly compiled from the following well-known Java coding standards documents shared by the respected global software vendors:
|
|
|
|
|
|
| URL | Vendor | Revision | Comments |
|
|
|
|-----|--------|----------|----------|
|
|
|
| https://github.com/spring-projects/spring-framework/wiki/Code-Style | **Spring** | 2019 | This document defines the coding standards for source files in the Spring Framework. It is primarily intended for the Spring Framework team but can be used as a reference by contributors. |
|
|
|
| https://google.github.io/styleguide/javaguide.html | **Google** | 2017 | This document serves as the **complete** definition of Google's coding standards for source code in the Java™ Programming Language. |
|
|
|
| https://github.com/47degrees/coding-guidelines/tree/master/java/spring | 47degrees | 2012 | Spring Coding Standards |
|
|
|
| https://github.com/47degrees/coding-guidelines/tree/master/java | 47degrees | 2012 | Java Coding Standards |
|
|
|
| https://www.oracle.com/java/technologies/javase/codeconventions-contents.html | Oracle (Sun) | 1999 | Java language coding standards presented in the Java Language Specification , from Sun Microsystems, Inc. |
|
|
|
| https://martinfowler.com/eaaCatalog/ | Martin Fowler | 2003 | Catalog of Patterns of Enterprise Application Architecture |
|
|
|
|
|
|
## Terminology Notes
|
|
|
In this document, unless otherwise clarified:
|
|
|
|
|
|
1. The term **class** is used inclusively to mean an "ordinary" class, enum class, interface, or annotation type (`@interface`)
|
|
|
1. The term **member** (of a class) is used inclusively to mean a nested class, field, method, or _constructor_; that is, all top-level contents of a class except initializers and comments
|
|
|
1. The term **comment** always refers to _implementation comments_. We do not use the phrase _documentation comments_, instead using the common term **Javadoc**
|
|
|
|
|
|
Other terminology notes will appear occasionally throughout the document.
|
|
|
|
|
|
## Code Style
|
|
|
|
|
|
### File Encoding: UTF-8
|
|
|
|
|
|
Source files must be encoded using UTF-8.
|
|
|
|
|
|
### Indentation
|
|
|
|
|
|
* Use tabs (not spaces)
|
|
|
* Use Unix (`LF`), not DOS (`CRLF`) line endings
|
|
|
* Eliminate all trailing whitespace
|
|
|
* On Linux, Mac, etc.: `find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;`
|
|
|
|
|
|
### Special Characters
|
|
|
|
|
|
#### Whitespace Characters
|
|
|
Aside from the line terminator sequence, the **ASCII horizontal space character (0x20)** is the only whitespace character that appears anywhere in a source file.
|
|
|
|
|
|
All other whitespace characters in string and character literals are escaped.
|
|
|
|
|
|
#### Special Escape Sequences
|
|
|
|
|
|
For any character that has a [special escape sequence](http://docs.oracle.com/javase/tutorial/java/data/characters.html) (`\b`, `\t`, `\n`, `\f`, `\r`, `\"`, `\'` and `\\`), that sequence is used rather than the corresponding octal (e.g. `\012`) or Unicode (e.g. `\u000a`) escape.
|
|
|
|
|
|
#### Non-ASCII Characters
|
|
|
|
|
|
For the remaining non-ASCII characters, either the actual Unicode character (e.g., `∞`) or the equivalent Unicode escape (e.g., `\u221e`) is used.
|
|
|
|
|
|
The choice depends only on which makes the code **easier to read and understand**, although Unicode escapes outside string literals and comments are strongly discouraged.
|
|
|
|
|
|
> **Tip:** In the Unicode escape case, and occasionally even when actual Unicode characters are used, an explanatory comment can be very helpful.
|
|
|
|
|
|
**Examples:**
|
|
|
|
|
|
```java
|
|
|
// Best: perfectly clear even without a comment
|
|
|
input String unitAbbrev = "μs";
|
|
|
|
|
|
// Allowed, but there is no reason to do this
|
|
|
String unitAbbrev = "\u03bcs"; // "μs"
|
|
|
|
|
|
// Allowed, but awkward and prone to mistakes
|
|
|
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"
|
|
|
|
|
|
// Poor: the reader has no idea what this is
|
|
|
String unitAbbrev = "\u03bcs";
|
|
|
|
|
|
// Good: use escapes for non-printable characters, and comment if necessary
|
|
|
return '\ufeff' + content; // byte order mark
|
|
|
```
|
|
|
|
|
|
> **Tip:** Never make your code less readable simply out of fear that some programs might not handle non-ASCII characters properly. If that should happen, those programs are **broken** and they must be **fixed**.
|
|
|
|
|
|
### Source File Structure
|
|
|
|
|
|
A source file consists of the following, in this exact order:
|
|
|
|
|
|
- License
|
|
|
- Package statement
|
|
|
- Import statements
|
|
|
- Exactly one top-level class
|
|
|
- Exactly one blank line separates each of the above sections.
|
|
|
|
|
|
### License
|
|
|
Each source file must specify the following license at the very top of the file:
|
|
|
|
|
|
```
|
|
|
*
|
|
|
* Copyright 2002-2019 the original author or authors.
|
|
|
*
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
* You may obtain a copy of the License at
|
|
|
*
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
|
*
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
* See the License for the specific language governing permissions and
|
|
|
* limitations under the License.
|
|
|
*
|
|
|
```
|
|
|
|
|
|
Always check the date range in the license header. For example, if you've modified a file in 2020 whose header still reads:
|
|
|
|
|
|
```
|
|
|
* Copyright 2002-2020 the original author or authors.
|
|
|
```
|
|
|
|
|
|
Then be sure to update it to 2021 accordingly:
|
|
|
|
|
|
```
|
|
|
* Copyright 2002-2021 the original author or authors.
|
|
|
```
|
|
|
|
|
|
### Import Statements
|
|
|
The import statements are structured as follows:
|
|
|
|
|
|
- Import java.*
|
|
|
- Blank line
|
|
|
- Import javax.*
|
|
|
- Blank line
|
|
|
- Import all other imports
|
|
|
- Blank line
|
|
|
- Import org.springframework.*
|
|
|
- Blank line
|
|
|
- Import static all other imports
|
|
|
|
|
|
Static imports should not be used in the production code. They should be used in the test code, especially for things like `import static org.assertj.core.api.Assertions.assertThat;`.
|
|
|
|
|
|
Wildcard imports such as `import java.util.*;` or `import static org.assertj.core.api.Assertions.*` are forbidden, even in the test code.
|
|
|
|
|
|
### Java Source File Organization
|
|
|
|
|
|
The following governs how the elements of a source file are organized:
|
|
|
|
|
|
1. Static fields
|
|
|
1. Normal fields
|
|
|
1. Constructors
|
|
|
1. (Private) methods called from constructors
|
|
|
1. Static factory methods
|
|
|
1. JavaBean properties (i.e., getters and setters)
|
|
|
1. Method implementations coming from interfaces
|
|
|
1. Private or protected templates that get called from method implementations coming from interfaces
|
|
|
1. Other methods
|
|
|
1. `equals`, `hashCode`, and `toString`
|
|
|
|
|
|
Note that private or protected methods called from method implementations should be placed immediately below the methods where they are used. In other words if there are three interface method implementations with three private methods (one used from each), then the order of methods should include one interface and one private method in sequence, not three interfacs and then three private methods at the bottom.
|
|
|
|
|
|
Above all, the organization of the code should feel _natural_.
|
|
|
|
|
|
### Formatting
|
|
|
|
|
|
#### One Statement per Line
|
|
|
|
|
|
Each statement is followed by a line break.
|
|
|
|
|
|
#### Braces
|
|
|
|
|
|
##### Block-Like Constructs: K&R Style
|
|
|
|
|
|
Braces mostly follow the _Kernighan and Ritchie style_ (a.k.a., Egyptian brackets) for nonempty blocks and block-like constructs:
|
|
|
|
|
|
- No line break before the opening brace but prefixed by a single space
|
|
|
- Line break after the opening brace
|
|
|
- Line break before the closing brace
|
|
|
- Line break after the closing brace if that brace terminates a statement or the body of a method, constructor, or named class
|
|
|
- Line break before else, catch and finally statements
|
|
|
|
|
|
Example:
|
|
|
|
|
|
```java
|
|
|
return new MyClass() {
|
|
|
@Override
|
|
|
public void method() {
|
|
|
if (condition()) {
|
|
|
something();
|
|
|
}
|
|
|
else {
|
|
|
try {
|
|
|
alternative();
|
|
|
}
|
|
|
catch (ProblemException ex) {
|
|
|
recover();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
```
|
|
|
|
|
|
##### Empty Blocks: May be Concise
|
|
|
|
|
|
An empty block or block-like construct may be in K & R style (as described above).
|
|
|
|
|
|
Alternatively, it may be closed immediately after it is opened, with no characters or line break in between (`{}`), **unless** it is part of a _multi-block statement_ (one that directly contains multiple blocks: `if/else` or `try/catch/finally`).
|
|
|
|
|
|
**Examples:**
|
|
|
|
|
|
```java
|
|
|
// This is acceptable
|
|
|
void doNothing() {}
|
|
|
|
|
|
// This is equally acceptable
|
|
|
void doNothingElse() {
|
|
|
}
|
|
|
// This is not acceptable: No concise empty blocks in a multi-block statement
|
|
|
try {
|
|
|
doSomething();
|
|
|
} catch (Exception e) {}
|
|
|
```
|
|
|
|
|
|
#### Line Wrapping
|
|
|
|
|
|
90 characters is the _preferred_ line length we aim for. In some case, the preferred length can be achieved by refactoring code slightly. In other cases it is just not possible.
|
|
|
|
|
|
90 is not a hard limit. Lines between 90-105 are perfectly acceptable in many cases where it aids readability and where wrapping has the opposite effect of reducing readability. This is a judgement call and it is also important to seek consistency. Many times you can learn by looking how specific situations are handled in other parts of the code.
|
|
|
|
|
|
Lines between 105-120 are allowed but discouraged and should be few.
|
|
|
|
|
|
No lines should exceed 120 characters.
|
|
|
|
|
|
The one big exception to the above line wrapping rules is Javadoc where we aim to wrap around 80 characters for maximum readability in all kinds of contexts, e.g., reading on Github, on your phone, etc.
|
|
|
|
|
|
When wrapping a lengthy expression, 90 characters is the length at which we aim to wrap. Put the separator symbols at the end of the line rather on the next line (comma separated arguments, etc). For instance:
|
|
|
|
|
|
```java
|
|
|
if (thisLengthyMethodCall(param1, param2) && anotherCheck() &&
|
|
|
yetAnotherCheck()) {
|
|
|
|
|
|
// ....
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Blank Lines
|
|
|
|
|
|
Add two blank lines before the following elements:
|
|
|
|
|
|
- `static {}` block
|
|
|
- Fields
|
|
|
- Constructors
|
|
|
- Inner classes
|
|
|
|
|
|
Add one blank line after a method signature that is multiline, i.e.
|
|
|
|
|
|
```java
|
|
|
@Override
|
|
|
protected Object invoke(FooBarOperationContext context,
|
|
|
AnotherSuperLongName name) {
|
|
|
|
|
|
// code here
|
|
|
}
|
|
|
```
|
|
|
|
|
|
For inner-classes, extra blank lines around fields and constructors are typically not added as the inner class is already separated by two lines, unless the inner class is more substantial in which case two extra lines could still help with readability.
|
|
|
|
|
|
### Class Declaration
|
|
|
|
|
|
Try as much as possible to put the implements, extends section of a class declaration on the same line as the class itself.
|
|
|
|
|
|
Order the classes so that the most important comes first.
|
|
|
|
|
|
### Naming
|
|
|
|
|
|
#### Constant Names
|
|
|
|
|
|
Constant names use `CONSTANT_CASE`: all uppercase letters, with words separated by underscores.
|
|
|
|
|
|
Every constant is a `static final` field, but not all `static final` fields are constants. Constant case should therefore be chosen only if the field **is really** a constant.
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
```java
|
|
|
// Constants
|
|
|
private static final Object NULL_HOLDER = new NullHolder();
|
|
|
public static final int DEFAULT_PORT = -1;
|
|
|
|
|
|
// Not constants
|
|
|
private static final ThreadLocal<Executor> executorHolder = new ThreadLocal<Executor>();
|
|
|
private static final Set<String> internalAnnotationAttributes = new HashSet<String>();
|
|
|
```
|
|
|
|
|
|
#### Variable Names
|
|
|
|
|
|
Avoid using single characters as variable names. For instance prefer `Method method` to `Method m`.
|
|
|
|
|
|
## Good Programming Practices
|
|
|
|
|
|
Good practice are a must at OSDU. Code is periodically reviewed for both machines and humans to ensure code quality meets standards within the community.
|
|
|
|
|
|
Pay special attention to the most common style error:
|
|
|
|
|
|
- Classes too long
|
|
|
- Methods too long
|
|
|
- Little or no Javadoc comments
|
|
|
- Swallow exceptions
|
|
|
- Multiple `return` statements
|
|
|
- Overuse of arrays in place of collections
|
|
|
- Too much or no whitespace
|
|
|
|
|
|
In the spirit of providing a guideline to avoid some of these errors and create better code the below listed points are cases with examples that should be considered at OSDU.
|
|
|
|
|
|
### Know Your Java
|
|
|
|
|
|
Spend some time getting to know the [core packages](https://docs.oracle.com/javase/8/docs/api/overview-summary.html) that are already a part of the SDK and avoid reinventing the wheel.
|
|
|
|
|
|
### File History
|
|
|
|
|
|
- A file should look like it was crafted by a single author, not like a history of changes
|
|
|
- Do not artificially spread things out that belong together
|
|
|
|
|
|
### Collections
|
|
|
|
|
|
Use the right collections for the right task.
|
|
|
|
|
|
#### Duplicates
|
|
|
|
|
|
- Allows duplicates: [List](http://docs.oracle.com/javase/6/docs/api/java/util/List.html)
|
|
|
- Does Not Allow Duplicates: [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html), [Map](http://docs.oracle.com/javase/6/docs/api/java/util/Map.html)
|
|
|
|
|
|
#### Implementations Iteration Order
|
|
|
|
|
|
- [HashSet](http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html) - undefined
|
|
|
- [HashMap](http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html) - undefined
|
|
|
- [LinkedHashSet](http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html) - insertion order
|
|
|
- [LinkedHashMap](http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html) - insertion order of keys
|
|
|
- [ArrayList](http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html) - insertion order
|
|
|
- [LinkedList](http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html) - insertion order
|
|
|
- [TreeSet](http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html) - ascending order (Comparable / Comparator)
|
|
|
|
|
|
### Raw Types
|
|
|
|
|
|
Avoid using raw types when using classes that support generics.
|
|
|
|
|
|
```java
|
|
|
/// Correct:
|
|
|
List<String> people = Arrays.asList("you", "me");
|
|
|
|
|
|
/// Incorrect:
|
|
|
List people = Arrays.asList("you", "me");
|
|
|
```
|
|
|
|
|
|
### Avoid Multiple `Return` Statements
|
|
|
|
|
|
Multiple `return` statements are hard and time consuming to debug.
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
public class StringUtils {
|
|
|
|
|
|
public static boolean isEmpty(String string) {
|
|
|
return string == null || "".equals(string.trim());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Correct:
|
|
|
public class StringUtils {
|
|
|
|
|
|
public static boolean isEmpty(String string) {
|
|
|
boolean empty = false;
|
|
|
if (string == null) {
|
|
|
empty = true;
|
|
|
} else if ("".equals(string.trim())) {
|
|
|
empty = true;
|
|
|
}
|
|
|
return empty;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Incorrect:
|
|
|
public class StringUtils {
|
|
|
|
|
|
public static boolean isEmpty(String string) {
|
|
|
if (string == null) {
|
|
|
return true;
|
|
|
} else if ("".equals(string.trim())) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Name Return Values `Result`
|
|
|
|
|
|
Consider using `result` as the name for the returned variable. This eases the pain when debugging and increases code legibility.
|
|
|
|
|
|
```java
|
|
|
public Object doSomething() {
|
|
|
Object result = null;
|
|
|
if (something) {
|
|
|
result = new Object();
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Boolean Comparisons
|
|
|
Mirroring the natural language, _if the current state is not active_ rather than _if active is not the current state_.
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
!active
|
|
|
|
|
|
// Incorrect:
|
|
|
active == false
|
|
|
```
|
|
|
|
|
|
### `for` Loops Vs `for-each` Loops
|
|
|
|
|
|
When iterating over iterable elements where the current index in the iteration is not important, `for-each` loops are preferred.
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
for (String name: names) {
|
|
|
doSomething(name);
|
|
|
}
|
|
|
|
|
|
// Incorrect:
|
|
|
for (int i = 0; i < names.length; i++) {
|
|
|
doSomething(names[i]);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### String Concatenation
|
|
|
Avoid using `+` or `+=` to concatenate strings. Use Java standards designed for that purposes such as String.format, StringBuilder, etc.
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
log.debug(String.format("found %s items", amount));
|
|
|
|
|
|
// Incorrect:
|
|
|
log.debug("found " + amount + " items");
|
|
|
```
|
|
|
|
|
|
### Organization of Setter Methods
|
|
|
|
|
|
Choose wisely where to add a new setter method; it should not be simply added at the end of the list. Perhaps the setter is related to another setter or relates to a group. In that case it should be placed near related methods.
|
|
|
|
|
|
- Setter order should reflect order of importance, not historical order
|
|
|
- Ordering of _fields_ and _setters_ should be **consistent**
|
|
|
|
|
|
### Ternary Operator
|
|
|
|
|
|
Wrap the ternary operator within parentheses, i.e., `return (foo != null ? foo : "default");`.
|
|
|
|
|
|
Also make sure that the _not null_ condition comes first.
|
|
|
|
|
|
### Null Checks
|
|
|
|
|
|
Use the `org.springframework.util.Assert.notNull` static method to check that a method argument is not `null`. Format the exception message so that the name of the parameter comes first with its first character capitalized, followed by _must not be null_. For instance,
|
|
|
|
|
|
```java
|
|
|
public void handle(Event event) {
|
|
|
Assert.notNull(event, "Event must not be null");
|
|
|
//...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Use of `final`
|
|
|
|
|
|
When implementing services and classes that are more than JavaBeans or objects to transfer data between layer, make sure you use the `final` keyword to communicate your intention regarding subclassing, use of constants and values that once set should be immutable.
|
|
|
|
|
|
```java
|
|
|
public final class ThisShouldNeverBeExtended {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
public final neverOverrideThisMethod() {
|
|
|
}
|
|
|
|
|
|
private final int thisFielfValueWillNeverChangeOnceSet;
|
|
|
|
|
|
final int thisLocalVariableValueWillNeverChangeOnceSet = 0;
|
|
|
```
|
|
|
|
|
|
### Use of `@Override`
|
|
|
|
|
|
Always add `@Override` on methods overriding or implementing a method declared in a super type.
|
|
|
|
|
|
### Use of `@since`
|
|
|
|
|
|
- `@since` should be added to every new class with the version of the framework in which it was introduced
|
|
|
- `@since` should be added to any _new_ **public** and **protected** methods of an existing class
|
|
|
|
|
|
### Utility Classes
|
|
|
|
|
|
A class that is only a collection of static utility methods must be named with a `Utils` suffix, must have a `private` default constructor, and must be `abstract`. Making the class `abstract` and providing a `private` _default_ constructor prevent anyone from instantiating it.
|
|
|
|
|
|
**Example:**
|
|
|
|
|
|
```java
|
|
|
public abstract MyUtils {
|
|
|
|
|
|
private MyUtils() {
|
|
|
/* prevent instantiation */
|
|
|
}
|
|
|
|
|
|
// static utility methods
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Field and Method References
|
|
|
|
|
|
A field of a class should _always_ be referenced using `this`. A method of class, however, should _never_ be referenced using `this`.
|
|
|
|
|
|
### Exceptions
|
|
|
|
|
|
Do not swallow exception, catch those you can recover or do something about, let the rest reach their destination
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
try {
|
|
|
do();
|
|
|
} catch (SomethingWeCanHandleException ex) {
|
|
|
log.error(ex);
|
|
|
notifyUser(ex);
|
|
|
} finally {
|
|
|
cleanUp();
|
|
|
}
|
|
|
|
|
|
// Correct:
|
|
|
public void doSomething() throws SomethingSomeoneElseCanHandleException {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
// Incorrect:
|
|
|
try {
|
|
|
do();
|
|
|
} catch (Throwable ex) {
|
|
|
log.error(ex);
|
|
|
}
|
|
|
try {
|
|
|
do();
|
|
|
} catch (SomethingWeCanHandleException ex) {
|
|
|
//do nothing
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### Exception: Intended Swallowing
|
|
|
|
|
|
Except as noted below, it is very rarely correct to do nothing in response to a caught exception. Typical responses are to log it, or if it is considered impossible, rethrow it as an `AssertionError`.
|
|
|
|
|
|
When it truly is appropriate to take no action whatsoever in a catch block, the reason this is justified is explained in a comment.
|
|
|
|
|
|
```java
|
|
|
try {
|
|
|
int i = Integer.parseInt(response);
|
|
|
return handleNumericResponse(i);
|
|
|
} catch (NumberFormatException ok) {
|
|
|
// it's not numeric; that's fine, just continue
|
|
|
}
|
|
|
return handleTextResponse(response);
|
|
|
```
|
|
|
|
|
|
#### Exception: In Tests
|
|
|
|
|
|
In tests a caught exception may be ignored without comment _if_ its name is or begins with `expected`.
|
|
|
|
|
|
The following is a very common idiom for ensuring that the code under test _does_ throw an exception of the expected type, so a comment is unnecessary here.
|
|
|
|
|
|
```java
|
|
|
try {
|
|
|
emptyStack.pop();
|
|
|
fail();
|
|
|
} catch (NoSuchElementException expected) {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Static Members: Qualified Using Class
|
|
|
|
|
|
When a reference to a static class member must be qualified, it is qualified with that class's name, not with a reference or expression of that class's type.
|
|
|
|
|
|
```java
|
|
|
Foo aFoo = ...;
|
|
|
Foo.aStaticMethod(); // good
|
|
|
aFoo.aStaticMethod(); // bad
|
|
|
somethingThatYieldsAFoo().aStaticMethod(); // very bad
|
|
|
```
|
|
|
|
|
|
### Finalizers: Not Used
|
|
|
|
|
|
It is **extremely rare** to override `Object.finalize`.
|
|
|
|
|
|
> **Tip:** Do not do it. If you absolutely must, first read and understand [_Effective Java_ Item 7](http://books.google.com/books?isbn=8131726592), _Avoid Finalizers_, very carefully, and _then_ do not do it.
|
|
|
|
|
|
## Design Patterns
|
|
|
|
|
|
Consider using common design patterns.
|
|
|
|
|
|
### Abstract Factory
|
|
|
|
|
|
Create or get an object without knowledge of its implementations, minimizing the refactoring effort and keeping implementations well defined and isolated into their classes.
|
|
|
|
|
|
```java
|
|
|
public interface PersistenceAdapter {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
public interface CassandraPersistenceAdapter extends PersistenceAdapter {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
public interface JPAPersistenceAdapter extends PersistenceAdapter {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
public class HibernateJPAPersistenceAdapterImpl implements JPAPersistenceAdapter {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
public class HectorCassandraPersistenceAdapterImpl implements CassandraPersistenceAdapter {
|
|
|
...
|
|
|
}
|
|
|
|
|
|
//Obtains the current runtime impl for the persistence adapter.
|
|
|
PersistenceAdapter persistenceAdapter = getPersistenceAdapter();
|
|
|
persistenceAdapter.save(user);
|
|
|
```
|
|
|
|
|
|
### Factory Method
|
|
|
|
|
|
Use static factory methods in objects where you may not create a new instance every time or you can return a subtype of the declared return type:
|
|
|
|
|
|
```java
|
|
|
Calendar.getInstance();
|
|
|
```
|
|
|
|
|
|
### Lazy Delegate Wrapper
|
|
|
|
|
|
When coding classes that represent response objects utilized in Views or other parts of the system where a subset of the properties may not be used consider the use of lazy wrappers with delegates keeping in mind the Serialization requirements.
|
|
|
|
|
|
```java
|
|
|
public class UserResponse {
|
|
|
|
|
|
private User delegate;
|
|
|
|
|
|
public UserResponse(User delegate) {
|
|
|
this.delegate = delegate;
|
|
|
}
|
|
|
|
|
|
public String getName() {
|
|
|
return delegate.getName();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Singleton
|
|
|
|
|
|
Use a singleton to represent a service class where there should be a single instance in the whole system.
|
|
|
|
|
|
```java
|
|
|
public class Earth {
|
|
|
|
|
|
private static Earth instance = new Earth();
|
|
|
|
|
|
private Earth() {
|
|
|
}
|
|
|
|
|
|
public static Earth getInstance() {
|
|
|
return instance;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
> ** Tip:** There is usually no need for implementing this pattern manually in web and backends where instances are managed by Spring or other IOC container.
|
|
|
|
|
|
### Enums
|
|
|
|
|
|
Constrain arguments by using type safe enumerations.
|
|
|
|
|
|
```java
|
|
|
// Correct:
|
|
|
public enum Options {
|
|
|
YES, NO
|
|
|
}
|
|
|
|
|
|
//Incorrect:
|
|
|
String yes = "YES";
|
|
|
String no = "NO";
|
|
|
```
|
|
|
|
|
|
### Private Helpers
|
|
|
|
|
|
Consider private helper methods to break down complex flows and long methods into more readable code.
|
|
|
|
|
|
```java
|
|
|
/// Correct:
|
|
|
public void downloadUrlContents(String url) {
|
|
|
checkIfHostIsReachable(url);
|
|
|
saveContentsToFile(url);
|
|
|
}
|
|
|
|
|
|
// Incorrect:
|
|
|
public void downloadUrlContents(String url) {
|
|
|
... complex code to see if a host is reachable
|
|
|
... complex code to turn the remote response into bytes and then serialize to disk
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Used Frameworks & Libraries
|
|
|
|
|
|
### Application Frameworks
|
|
|
|
|
|
| Name (URL) | Maven Dependency Group | Maven Dependency Artifact(s) | Min. Version | Purpose |
|
|
|
|---|---|---|---|---|
|
|
|
| [Spring Boot](https://spring.io/projects/spring-boot) | org.springframework.boot | spring-boot-* | 2.2 | Platform for auto configurable production-grade Spring applications. Built on top of the Spring framework. Comes with many dependencies. Auto-configures Spring and 3rd party libraries whenever possible.|
|
|
|
| [Spring Aspects](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop) | org.springframework | [spring-aspects](https://mvnrepository.com/artifact/org.springframework/spring-aspects) | 5.2.8 | Aspect Oriented Programming with Spring |
|
|
|
| [Spring Retry](https://docs.spring.io/spring-batch/docs/current/reference/html/retry.html) | org.springframework.retry | [spring-retry](https://mvnrepository.com/artifact/org.springframework.retry/spring-retry) | 1.2.5 | To automate retry operations |
|
|
|
| [springdoc-openapi](https://springdoc.org/) | org.springdoc | [springdoc-openapi-ui](https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui) | 1.4.8 | Generation of API documentation. Supports: OpenAPI 3; Spring-boot; JSR-303; Swagger-ui; OAuth 2 |
|
|
|
| [Elasticsearch REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-api.html) | org.elasticsearch.client | [elasticsearch-rest-client](https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-client) (deprecated), [elasticsearch-rest-high-level-client](https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client) | 7.8.1 | Elasticsearch REST client |
|
|
|
| [RabbitMQ Java Client](https://www.rabbitmq.com/java-client.html) | com.rabbitmq | [amqp-client]https://mvnrepository.com/artifact/com.rabbitmq/amqp-client | 5.7.3 | The RabbitMQ Java client library allows Java and JVM-based applications to connect to and interact with RabbitMQ nodes. |
|
|
|
| [MinIo](https://docs.min.io/docs/java-client-api-reference.html) | io.minio | [minio](https://mvnrepository.com/artifact/io.minio/minio) | 7.1.4 | JDK for MinIo (Amazon S3 compatible server-side storage stack) |
|
|
|
| [Spring Data MongoDB](https://spring.io/projects/spring-data-mongodb) | org.springframework.boot | [spring-boot-starter-data-mongodb](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb) | 2.1.16 | Provides integration with the MongoDB document database |
|
|
|
| [Lombok](https://projectlombok.org/) | org.projectlombok | [lombok](https://mvnrepository.com/artifact/org.projectlombok/lombok) | 1.18 | Automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more. |
|
|
|
| [Gson](https://github.com/google/gson/blob/master/UserGuide.md) | com.google.code.gson | [gson](https://mvnrepository.com/artifact/com.google.code.gson/gson) | 2.8.5 Library for Java to JSON conversion |
|
|
|
| [Guava](https://github.com/google/guava) | com.google.guava | [guava](https://mvnrepository.com/artifact/com.google.guava/guava) | 27.1 | Google Core Libraries for Java |
|
|
|
|
|
|
### Test Frameworks
|
|
|
|
|
|
| Name (URL) | Maven Dependency Group | Maven Dependency Artifact(s) | Min. Version | Purpose |
|
|
|
|---|---|---|---|---|
|
|
|
| [Junit 5](https://junit.org/junit5/docs/current/user-guide/) | org.junit.platform, org.junit.jupiter, org.junit.vintage | [junit-platform-runner](https://mvnrepository.com/artifact/org.junit.platform/junit-platform-runner), [junit-jupiter](https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter), [junit-vintage-engine](https://mvnrepository.com/artifact/org.junit.vintage/junit-vintage-engine) | 5.5 | Unit Test Platform |
|
|
|
| [Spring Test](https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html) | org.springframework | [spring-test](https://mvnrepository.com/artifact/org.springframework/spring-test) | 5.2.7 | Spring TestContext Framework for Unit and Integration testing |
|
|
|
| [Power Mock](https://github.com/powermock/powermock) | org.powermock | [powermock-api-mockito2](https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2) | 1.7.3 | Enables mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more |
|
|
|
| [Cucumber](https://cucumber.io/docs/installation/java/) | [io.cucumber](https://mvnrepository.com/artifact/io.cucumber) | [cucumber-java8](https://mvnrepository.com/artifact/io.cucumber/cucumber-java8) | 5.4.0 | Cucumber JVM: Java 8 |
|
|
|
|
|
|
## Javadoc
|
|
|
|
|
|
### Javadoc Formatting
|
|
|
|
|
|
#### General Form
|
|
|
|
|
|
The following template summarizes a typical use for the Javadoc of a method:
|
|
|
|
|
|
```
|
|
|
/**
|
|
|
* Parse the specified {@link Element} and register the resulting
|
|
|
* {@link BeanDefinition BeanDefinition(s)}.
|
|
|
* <p>Implementations must return the primary {@link BeanDefinition} that results
|
|
|
* from the parsing if they will ever be used in a nested fashion (for example as
|
|
|
* an inner tag in a {@code <property/>} tag). Implementations may return
|
|
|
* {@code null} if they will <strong>not</strong> be used in a nested fashion.
|
|
|
* @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions}
|
|
|
* @param parserContext the object encapsulating the current state of the parsing process;
|
|
|
* provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
|
|
|
* @return the primary {@link BeanDefinition}
|
|
|
*/
|
|
|
BeanDefinition parse(Element element, ParserContext parserContext);
|
|
|
```
|
|
|
|
|
|
In particular, please note:
|
|
|
- Use an imperative style (i.e. _Return_ and not _Returns_) for the first sentence
|
|
|
- No blank lines between the description and the parameter descriptions
|
|
|
- If the description is defined with multiple paragraphs, start each of them with `<p>`
|
|
|
- If a parameter description needs to be wrapped, do not indent subsequent lines (see `parserContext`)
|
|
|
|
|
|
The Javadoc of a class has some extra rules that are illustrated by the sample below:
|
|
|
|
|
|
```
|
|
|
/*
|
|
|
* Interface used by the {@link DefaultBeanDefinitionDocumentReader} to handle custom,
|
|
|
* top-level (directly under {@code <beans/>}) tags.
|
|
|
*
|
|
|
* <p>Implementations are free to turn the metadata in the custom tag into as many
|
|
|
* {@link BeanDefinition BeanDefinitions} as required.
|
|
|
*
|
|
|
* <p>The parser locates a {@link BeanDefinitionParser} from the associated
|
|
|
* {@link NamespaceHandler} for the namespace in which the custom tag resides.
|
|
|
*
|
|
|
* @author Rob Harrop
|
|
|
* @since 2.0
|
|
|
* @see NamespaceHandler
|
|
|
* @see AbstractBeanDefinitionParser
|
|
|
*/
|
|
|
```
|
|
|
|
|
|
- Each class must have a `@since` tag with the version in which the class was introduced.
|
|
|
- The order of tags for class-level Javadoc is `@author`, `@since`, and `@see`.
|
|
|
- In contrast to method-level Javadoc, the paragraphs of a class description _are_ separated by blank lines.
|
|
|
|
|
|
The following are additional general rules to apply when writing Javadoc:
|
|
|
- Use `{@code}` to wrap code statements or values such as `null`
|
|
|
- If a type is only referenced by a `{@link}` element, use the fully qualified name in order to avoid an unnecessary `import` declaration
|
|
|
|
|
|
#### Paragraphs
|
|
|
|
|
|
One blank line—that is, a line containing only the aligned leading asterisk (*)—appears between paragraphs, and before the group of block tags if present. Each paragraph but the first has `<p>` immediately before the first word, with no space after.
|
|
|
|
|
|
#### Block Tags
|
|
|
|
|
|
Any of the standard block tags that are used appear in the order `@param`, `@return`, `@throws`, `@deprecated`, and these four types never appear with an empty description. When a block tag does not fit on a single line, continuation lines are indented four (or more) spaces from the position of the `@.`
|
|
|
|
|
|
### The Summary Fragment
|
|
|
|
|
|
Each Javadoc block begins with a brief **summary fragment**. This fragment is very important: it is the only part of the text that appears in certain contexts such as class and method indexes.
|
|
|
|
|
|
This is a fragment—a noun phrase or verb phrase, not a complete sentence. It does not begin with _A {@code Foo} is a..._, or _This method returns..._, nor does it form a complete imperative sentence like _Save the record._. However, the fragment is capitalized and punctuated as if it were a complete sentence.
|
|
|
|
|
|
### Where Javadoc Is Used
|
|
|
|
|
|
At the _minimum_, Javadoc is present for every `public` class, and every `public` or `protected` member of such a class, with a few exceptions noted below.
|
|
|
|
|
|
Additional Javadoc content may also be present, as explained [below](#non-required-javadoc).
|
|
|
|
|
|
#### Exception: Self-Explanatory Methods
|
|
|
|
|
|
Javadoc is optional for "simple, obvious" methods like `getFoo`, in cases where there _really and truly_ is nothing else worthwhile to say but "Returns the foo".
|
|
|
|
|
|
> **Important:** It is not appropriate to cite this exception to justify omitting relevant information that a typical reader might need to know. For example, for a method named `getCanonicalName`, do not omit its documentation (with the rationale that it would say only `/** Returns the canonical name. */`) if a typical reader may have no idea what the term "canonical name" means!
|
|
|
|
|
|
#### Exception: Overrides
|
|
|
|
|
|
Javadoc is not always present on a method that overrides a supertype method.
|
|
|
|
|
|
#### Non-Required Javadoc
|
|
|
Other classes and members have Javadoc as _needed_ or _desired_.
|
|
|
|
|
|
Whenever an implementation comment would be used to define the overall purpose or behavior of a class or member, that comment is written as Javadoc instead (using /**).
|
|
|
|
|
|
## Tests
|
|
|
|
|
|
### Testing Framework
|
|
|
|
|
|
Tests must be written using JUnit Jupiter (a.k.a., JUnit 5).
|
|
|
|
|
|
The only exceptions to the above rule are test classes in the `spring-test` module that specifically test Spring's integration with JUnit 4 and TestNG.
|
|
|
|
|
|
### Naming
|
|
|
|
|
|
Each test class name must end with a `Tests` suffix.
|
|
|
|
|
|
### Assertions
|
|
|
|
|
|
Use AssertJ for assertions.
|
|
|
|
|
|
### Mocking
|
|
|
|
|
|
Use the BDD Mockito support. |