Just clone the repository and you're ready to go (please see prerequisites section). You'll get a nice template for an empty Spring Boot 3 application.
Highly opinionated build with selection of Maven plugins made accessible via the Netbeans UI.
See section 'Source code style' for more information about the coding style.
For a Git commit message template see the section 'Commit message format'.
The two projects in spring-boot-netbeans-single-module
and spring-boot-netbeans-multi-module
can be used as templates.
Both projects use ${revision}
for setting the version which can be overridden at build time from the outside.
In order to speed up the IDE actions as much as possible use the Maven Daemon.
Also [Run], [Debug], and [Test] skip all not necessary plugins.
This is done with the maven-skip-execution-profile-extension
that automatically creates the (runtime) profiles needed for skipping certain plugins actions.
The profiles don't end up in the actual POM.
"Compile on Save" is currently disabled.
The idea is to always use the Java compiler because recently CoS fell more and more out of favour (see disable compile-on-save by default in maven projects #5826).
javac
has no incremental compilation and might get too slow for bigger projects.
To test if the Eclipse compiler (which is able to do incremental compilation) performs better a profile called eclipse
is included.
- [Build]
install
withresources:[test]Resources
andcompiler:[test]Compile
only - [Clean and Build]
clean install
withresources:[test]Resources
andcompiler:[test]Compile
only - [Run]
spring-boot:run
- [Debug]
spring-boot:run
with debugger attached - Run Maven
- [Full Build] a full
clean install
with verification - [Format Code]
spring-javaformat:apply
andimpsort:sort
- [Integration Test]
failsafe:integration-test
- [Test Gap Analysis (Unit Test only)]
test-gap-analysis:perform
of current working tree changes with unit tests only - [Test Gap Analysis]
test-gap-analysis:perform
of current working tree changes with unit and integration tests - [Mutation Coverage]
pitest-maven:mutationCoverage
of unit tests only - [Static Code Analysis]
spotbugs:check
,checkstyle:check
,pmd:check
,pmd:cpd-check
andarch-unit:arch-test
- [Checkstyle]
checkstyle:check
- [PMD]
pmd:check
- [Clone Detection]
pmd:cpd-check
- [ArchUnit Maven plugin]
arch-unit:arch-test
- [Forbidden API Checker]
forbiddenapis:check
- [Dependency Tree]
dependency:tree
- [Dependency Graph]
depgraph:graph
- [POM Hierarchy Tree]
hierarchy:tree
- [Sortpom]
sortpom:sorty
- [Enforce Dependency Convergence]
enforcer:enforce@dependency-convergence
- [Available Dependency Updates]
versions:display-dependency-updates
- [Source Lines of Code]
sloc-maven-plugin:sloc
- [Full Build] a full
-
clone the repository with
git clone --config core.autocrlf=input
to avoid line ending problems on Windows (the formatters are usingLR
) -
JDK 17
-
recent Maven (tested with 3.9.5), the Maven Daemon is recommended to speed up the IDE actions
-
Netbeans (tested with 19)
-
mvn clean install
inskip-execution-profile/maven-skip-execution-profile-extension
directory of this repository -
mvn clean install
of Pocketsaw 1.7.1 -
[optional] External Code Formatters for NetBeans to apply the Spring Java Format directly in the IDE
- NOTE: It is important that the version of the
io.spring.javaformat:spring-javaformat-formatter
andorg.eclipse.jdt:org.eclipse.jdt.core
dependencies of the plugin are matching the version of the used Maven plugin. Otherwise the format could be slightly different. Check the URL mentioned in https://github.com/spring-io/spring-javaformat/blob/main/pom.xml#L35 under plugins for the exact version oforg.eclipse.jdt.core
to use.
- NOTE: It is important that the version of the
-
[optional]
mvn clean install
of Test Gap Analysis 1.2.1
- avoid
static
methods for easier testing- exception: (package) private helper methods in classes that are static to enforce functional purity
- exception: completely stateless
*Utils
classes with static methods only- utility classes must be
abstract
and have a private default constructor
- utility classes must be
- exception: real constants with names in upper case delimited by underscores (real constants are either primitive or immutable instances that are never used together with a
"."
to access one of their members)
logger
has to be:private static final Logger logger = LoggerFactory.getLogger(getClass());
(see https://www.slf4j.org/faq.html#declared_static for no conclusion... 😉)- restrict file, method and lambda lengths to reasonable values
- code dependency
- no code cycles on package level
- no dependencies between a package and any of its (sub-)sub-packages (only the other way around)
- restrict maximal number of parameters to a reasonable value
- in case of model class constructors with too many parameters use a http://rdafbn.blogspot.com/2012/07/step-builder-pattern_28.html
- extra abstract class with
<ModelClassName>Builder
name and private default constructor - static
builder()
method in model class as only way to instantiate the class - (package private) constructor in model class with
BuilderImpl
as only parameter - inner step interfaces in
<ModelClassName>Builder
withStep
suffix - inner static class
BuilderImpl
implementing all the steps
- extra abstract class with
- in case of model class constructors with too many parameters use a http://rdafbn.blogspot.com/2012/07/step-builder-pattern_28.html
- usage of immutable data structures only by making all members
final
- usage of Java records when ever possible
- for members of type collection defensive copies and
Collections.unmodifiableXzy(...)
in constructor- the elements in the collections must also be immutable
- local variables and parameters must not use
final
because it adds too much noise (see https://github.com/spring-io/spring-javaformat#final)- only ever mutate parameters in
private
methods (for example recursive methods), for all other methods return proper result types
- only ever mutate parameters in
- usage of
Optional<?>
(was actually designed for method return types only, but is the only JDK built-in way to indicate a nullable value (all@Nullable
annotations are from third-party libraries))- never return
null
, useOptional<?>
instead (this eliminates the need fornull
checks everywhere) - but prefer method overloading or usage of a builder over
Optional<?>
method parameters - even use
Optional<?>
for immutable class fields or record components (avoids unnecessaryOptional.ofNullable(...)
calls in getters)
- never return
- Java source file organization (derived from https://github.com/spring-projects/spring-framework/wiki/Code-Style#java-source-file-organization)
enum
types if simple ones (contains only constants)static
fields and initializers- normal fields
- constructors (ordering of parameters should be consistent with the order of the corresponding fields)
static
factory methods- all other methods
- overridden methods have to be grouped together
- getters and setters (ordering of fields and getters/setters should be consistent with order of the corresponding fields)
equals(...)
,hashCode()
andtoString()
- inner types (
static
/inner classes,interface
and non-simpleenum
types)- don't overuse inner types, as soon as the type is also useful in some other context it should be a top-level type
- don't use checked (and unchecked) exceptions for program flow, always prefer returning proper result types (exceptions are reserved for real, unexpected errors)
- usage of the
Result
type ofcom.spencerwi:Either.java
to return either a return type or the exception that happened - wrapping an
IOException
withUncheckedIOException
(or more general any exception in aIllegalStateException
) is okay but takes away the possibility from the caller to react to errors (for example by skipping a single file that cause anIOException
while reading it)
- usage of the
- no static imports in production code (only allowed in tests)
- no wildcard imports in general
equals(...)
,hashCode()
andtoString()
must be implemented for all model/domain classes but not service or utility classestoString()
should only be used for debugging purposes (printed in logs (DEBUG
level) or in IDE) and never use to extract the state of an objecttoString()
should contain all interesting information (too long information can be shorten or summarized)- on high-level
equals(...)
must first test for identity (==
) and then for type compatibility withinstanceof
equals(...)
must compare different type of fields differently:float
anddouble
withFloat.compare(...)
resp.Double.compare(...)
- all other primitive types and enums with
==
- object references with
Objects.equals(...)
hashCode()
must useObjects.hash(...)
- always use
this.
for class fields but never for instance methods (same approach as https://github.com/spring-projects/spring-framework/wiki/Code-Style#field-and-method-references) static
fields and methods of own class must never be prefixed with the own class name- usage of Java Stream API
- don't overuse lambdas with streams, prefer method references or simple one line lambdas
- usage of
forEach
withstream()
is suspicious, should only be used in rare cases with a method reference (good old for-each loops might be easier to read and debug)
- no usage of
var
at all because the diamond operator does a good enough job (the Spring teams agrees: https://github.com/spring-projects/spring-framework/wiki/Code-Style#local-variable-type-inference) - be careful with static initializers that perform heavy operations, they might slow down app start
- prefer lazy instantiation with either https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom or a simple singleton with a
synchronnized
block
- prefer lazy instantiation with either https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom or a simple singleton with a
- whenever a
Locale
is required useLocale.ROOT
(e.g.String#toLowerCase(Locale)
)
All messages must adhere to the following format:
summary (use same summary to group multiple commits)
- change details as unordered Markdown list
- with multiple levels to group things
- single backticks for `code`
The blank line between summary and details is mandatory. Details are always a Markdown syntax unordered list. In the list items only plain text and Markdown code is allowed. Lower case is in general preferred, only proper names should be capitalized.