Opinionated java-library project template

feat: initial commit

+898
+101
.checkstyle/checkstyle.xml
··· 1 + <?xml version="1.0"?> 2 + <!DOCTYPE module PUBLIC 3 + "-//Puppy Crawl//DTD Check Configuration 1.3//EN" 4 + "https://checkstyle.org/dtds/configuration_1_3.dtd"> 5 + 6 + <module name="Checker"> 7 + 8 + <property name="charset" value="UTF-8"/> 9 + <property name="fileExtensions" value="java, properties, xml"/> 10 + <property name="severity" value="error"/> 11 + 12 + <!-- https://checkstyle.org/filefilters/beforeexecutionexclusionfilefilter.html --> 13 + <module name="BeforeExecutionExclusionFileFilter"> 14 + <property name="fileNamePattern" value="module\-info\.java$"/> 15 + </module> 16 + 17 + <!-- https://checkstyle.org/checks/whitespace/filetabcharacter.html --> 18 + <module name="FileTabCharacter"> 19 + <property name="eachLine" value="true"/> 20 + </module> 21 + 22 + <!-- https://checkstyle.org/checks/misc/newlineatendoffile.html --> 23 + <module name="NewlineAtEndOfFile"/> 24 + 25 + <!-- https://checkstyle.org/filters/suppressionfilter.html --> 26 + <module name="SuppressionFilter"> 27 + <property name="file" value="${configDirectory}/suppressions.xml"/> 28 + </module> 29 + 30 + <!-- https://checkstyle.org/filters/suppresswarningsfilter.html --> 31 + <module name="SuppressWarningsFilter"/> 32 + 33 + <module name="TreeWalker"> 34 + 35 + <!-- https://checkstyle.org/checks/misc/arraytypestyle.html --> 36 + <module name="ArrayTypeStyle"/> 37 + 38 + <!-- https://checkstyle.org/checks/imports/avoidstarimport.html --> 39 + <module name="AvoidStarImport"/> 40 + 41 + <!-- https://checkstyle.org/checks/design/finalclass.html --> 42 + <module name="FinalClass"/> 43 + 44 + <!-- https://checkstyle.org/checks/coding/finallocalvariable.html --> 45 + <module name="FinalLocalVariable"> 46 + <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF"/> 47 + <property name="validateEnhancedForLoopVariable" value="true"/> 48 + </module> 49 + 50 + <!-- https://checkstyle.org/checks/imports/illegalimport.html --> 51 + <module name="IllegalImport"> 52 + <property name="illegalPkgs" 53 + value="sun, jdk, com.sun, org.jetbrains.annotations.Nullable, org.jetbrains.annotations.NotNull"/> 54 + </module> 55 + 56 + <!-- https://checkstyle.org/checks/javadoc/invalidjavadocposition.html --> 57 + <module name="InvalidJavadocPosition"/> 58 + 59 + <!-- https://checkstyle.org/checks/javadoc/javadoccontentlocation.html --> 60 + <module name="JavadocContentLocation"/> 61 + 62 + <!-- https://checkstyle.org/checks/javadoc/javadocmethod.html --> 63 + <module name="JavadocMethod"/> 64 + 65 + <!-- https://checkstyle.org/checks/javadoc/javadocmissingwhitespaceafterasterisk.html --> 66 + <module name="JavadocMissingWhitespaceAfterAsterisk"/> 67 + 68 + <!-- https://checkstyle.org/checks/javadoc/javadocparagraph.html --> 69 + <module name="JavadocParagraph"/> 70 + 71 + <!-- https://checkstyle.org/checks/javadoc/javadoctagcontinuationindentation.html --> 72 + <module name="JavadocTagContinuationIndentation"/> 73 + 74 + <!-- https://checkstyle.org/checks/blocks/leftcurly.html --> 75 + <module name="LeftCurly"/> 76 + 77 + <!-- https://checkstyle.org/checks/coding/matchxpath.html --> 78 + <module name="MatchXpath"> 79 + <property name="query" value="//ANNOTATION[./IDENT[@text='NotNull']]"/> 80 + <message key="matchxpath.match" 81 + value="Avoid using @NotNull annotation. Use @NonNull instead."/> 82 + </module> 83 + 84 + <!-- https://checkstyle.org/config_naming.html#MethodName --> 85 + <module name="MethodName"> 86 + <property name="format" 87 + value="^(?:(?:.{1,3})|(?:[gs]et[^A-Z].*)|(?:(?:[^gsA-Z]..|.[^e].|..[^t]).+))$"/> 88 + </module> 89 + 90 + <!-- https://checkstyle.org/checks/coding/requirethis.html --> 91 + <module name="RequireThis"/> 92 + 93 + <!-- https://checkstyle.org/filters/suppresswarningsfilter.html --> 94 + <module name="SuppressWarningsHolder"/> 95 + 96 + <!-- https://checkstyle.org/filters/suppressioncommentfilter.html --> 97 + <module name="SuppressionCommentFilter"/> 98 + 99 + </module> 100 + 101 + </module>
+6
.checkstyle/suppressions.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" 3 + "http://checkstyle.org/dtds/suppressions_1_2.dtd"> 4 + <suppressions> 5 + 6 + </suppressions>
+12
.editorconfig
··· 1 + [*] 2 + charset = utf-8 3 + end_of_line = lf 4 + indent_size = 4 5 + indent_style = space 6 + insert_final_newline = true 7 + max_line_length = 100 8 + tab_width = 4 9 + ij_continuation_indent_size = 4 10 + ij_smart_tabs = false 11 + ij_java_blank_lines_before_class_end = 1 12 + ij_any_blank_lines_after_class_header = 1
+2
.gitattributes
··· 1 + * text=auto 2 + *.java text eol=lf
+6
.gitignore
··· 1 + **/build 2 + **/.gradle 3 + **/.idea 4 + **/.iml 5 + **/run 6 + **/.kotlin
+160
.scripts/rename-template.sh
··· 1 + #!/usr/bin/env bash 2 + set -euo pipefail 3 + 4 + usage() { 5 + cat <<'EOF' 6 + Usage: ./scripts/rename-template.sh -g <groupId> -p <projectName> 7 + 8 + Examples: 9 + ./scripts/rename-template.sh -g com.acme -p my-project 10 + EOF 11 + } 12 + 13 + GROUP_ID="" 14 + PROJECT_NAME="" 15 + PACKAGE_NAME="" 16 + 17 + while getopts ":g:p:h" opt; do 18 + case "$opt" in 19 + g) GROUP_ID="$OPTARG" ;; 20 + p) PROJECT_NAME="$OPTARG" ;; 21 + h) 22 + usage 23 + exit 0 24 + ;; 25 + \?) 26 + echo "Unknown option: -$OPTARG" >&2 27 + usage 28 + exit 1 29 + ;; 30 + :) 31 + echo "Missing argument for -$OPTARG" >&2 32 + usage 33 + exit 1 34 + ;; 35 + esac 36 + done 37 + 38 + if [[ -z "$GROUP_ID" || -z "$PROJECT_NAME" ]]; then 39 + usage 40 + exit 1 41 + fi 42 + 43 + PROJECT_NAME="${PROJECT_NAME##.}" 44 + if [[ -z "$PROJECT_NAME" ]]; then 45 + echo "Project name cannot be only dots." >&2 46 + exit 1 47 + fi 48 + 49 + normalize_segment() { 50 + local segment="$1" 51 + local normalized 52 + normalized="$(echo "$segment" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_]/_/g')" 53 + normalized="${normalized##_}" 54 + normalized="${normalized%%_}" 55 + if [[ -z "$normalized" ]]; then 56 + normalized="app" 57 + fi 58 + echo "$normalized" 59 + } 60 + 61 + package_segments=() 62 + IFS='.' read -r -a group_parts <<<"$GROUP_ID" 63 + for part in "${group_parts[@]}"; do 64 + package_segments+=("$(normalize_segment "$part")") 65 + done 66 + package_segments+=("$(normalize_segment "$PROJECT_NAME")") 67 + PACKAGE_NAME="$(IFS='.'; echo "${package_segments[*]}")" 68 + 69 + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" 70 + TEMPLATE_PACKAGE="com.example.template" 71 + TEMPLATE_GROUP="com.example" 72 + 73 + FILES=( 74 + "$REPO_ROOT/build.gradle.kts" 75 + "$REPO_ROOT/settings.gradle.kts" 76 + "$REPO_ROOT/readme.md" 77 + "$REPO_ROOT/build-logic/src/main/kotlin/extensions.kt" 78 + ) 79 + 80 + if [[ -d "$REPO_ROOT/api/src/main/java" ]]; then 81 + while IFS= read -r -d '' file; do 82 + FILES+=("$file") 83 + done < <(find "$REPO_ROOT/api/src/main/java" -type f -print0) 84 + fi 85 + 86 + if [[ -d "$REPO_ROOT/api/src/test/java" ]]; then 87 + while IFS= read -r -d '' file; do 88 + FILES+=("$file") 89 + done < <(find "$REPO_ROOT/api/src/test/java" -type f -print0) 90 + fi 91 + 92 + SED_INPLACE=(-i) 93 + if [[ "$(uname)" == "Darwin" ]]; then 94 + SED_INPLACE=(-i '') 95 + fi 96 + 97 + replace_in_file() { 98 + local file="$1" 99 + local safe_package safe_group safe_project 100 + safe_package="${PACKAGE_NAME//\\/\\\\}" 101 + safe_package="${safe_package//&/\\&}" 102 + safe_package="${safe_package//\//\\/}" 103 + safe_group="${GROUP_ID//\\/\\\\}" 104 + safe_group="${safe_group//&/\\&}" 105 + safe_group="${safe_group//\//\\/}" 106 + safe_project="${PROJECT_NAME//\\/\\\\}" 107 + safe_project="${safe_project//&/\\&}" 108 + safe_project="${safe_project//\//\\/}" 109 + sed "${SED_INPLACE[@]}" \ 110 + -e "s/com\.example\.template/$safe_package/g" \ 111 + -e "s/com\.example/$safe_group/g" \ 112 + -e "s/template/$safe_project/g" \ 113 + "$file" 114 + } 115 + 116 + for file in "${FILES[@]}"; do 117 + [[ -f "$file" ]] || continue 118 + replace_in_file "$file" 119 + echo "Updated: $file" 120 + done 121 + 122 + OLD_PACKAGE_DIR="$REPO_ROOT/api/src/main/java/$(echo "$TEMPLATE_PACKAGE" | tr '.' '/')" 123 + if [[ -d "$OLD_PACKAGE_DIR" ]]; then 124 + NEW_PACKAGE_DIR="$REPO_ROOT/api/src/main/java/$(echo "$PACKAGE_NAME" | tr '.' '/')" 125 + mkdir -p "$NEW_PACKAGE_DIR" 126 + shopt -s dotglob nullglob 127 + mv "$OLD_PACKAGE_DIR"/* "$NEW_PACKAGE_DIR"/ 128 + shopt -u dotglob nullglob 129 + rmdir "$OLD_PACKAGE_DIR" 2>/dev/null || true 130 + 131 + OLD_GROUP_DIR="$REPO_ROOT/api/src/main/java/$(echo "$TEMPLATE_GROUP" | tr '.' '/')" 132 + if [[ -d "$OLD_GROUP_DIR" && -z "$(find "$OLD_GROUP_DIR" -type f -o -type d | tail -n 1)" ]]; then 133 + rmdir "$OLD_GROUP_DIR" 2>/dev/null || true 134 + fi 135 + fi 136 + 137 + if [[ -d "$REPO_ROOT/api/src/main/java" ]]; then 138 + find "$REPO_ROOT/api/src/main/java" -type d -empty -delete 139 + fi 140 + 141 + OLD_TEST_PACKAGE_DIR="$REPO_ROOT/api/src/test/java/$(echo "$TEMPLATE_PACKAGE" | tr '.' '/')" 142 + if [[ -d "$OLD_TEST_PACKAGE_DIR" ]]; then 143 + NEW_TEST_PACKAGE_DIR="$REPO_ROOT/api/src/test/java/$(echo "$PACKAGE_NAME" | tr '.' '/')" 144 + mkdir -p "$NEW_TEST_PACKAGE_DIR" 145 + shopt -s dotglob nullglob 146 + mv "$OLD_TEST_PACKAGE_DIR"/* "$NEW_TEST_PACKAGE_DIR"/ 147 + shopt -u dotglob nullglob 148 + rmdir "$OLD_TEST_PACKAGE_DIR" 2>/dev/null || true 149 + 150 + OLD_TEST_GROUP_DIR="$REPO_ROOT/api/src/test/java/$(echo "$TEMPLATE_GROUP" | tr '.' '/')" 151 + if [[ -d "$OLD_TEST_GROUP_DIR" && -z "$(find "$OLD_TEST_GROUP_DIR" -type f -o -type d | tail -n 1)" ]]; then 152 + rmdir "$OLD_TEST_GROUP_DIR" 2>/dev/null || true 153 + fi 154 + fi 155 + 156 + if [[ -d "$REPO_ROOT/api/src/test/java" ]]; then 157 + find "$REPO_ROOT/api/src/test/java" -type d -empty -delete 158 + fi 159 + 160 + echo "Done. GroupId=$GROUP_ID ProjectName=$PROJECT_NAME PackageName=$PACKAGE_NAME"
+7
api/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + api(libs.jspecify) 7 + }
api/src/main/java/com/example/template/api/.gitkeep

This is a binary file and will not be displayed.

+39
api/src/test/java/com/example/template/TemplateTest.java
··· 1 + /* 2 + * This file is part of <project name>, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.example.template; 25 + 26 + import static org.junit.jupiter.api.Assertions.assertTrue; 27 + 28 + import org.jspecify.annotations.NullMarked; 29 + import org.junit.jupiter.api.Test; 30 + 31 + @NullMarked 32 + class TemplateTest { 33 + 34 + @Test 35 + void testTemplate() { 36 + assertTrue(true); 37 + } 38 + 39 + }
+16
build-logic/build.gradle.kts
··· 1 + plugins { 2 + `kotlin-dsl` 3 + } 4 + 5 + repositories { 6 + gradlePluginPortal() 7 + } 8 + 9 + dependencies { 10 + implementation(libs.shadow) 11 + implementation(libs.indra.common) 12 + implementation(libs.indra.licenseHeader) 13 + 14 + // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 15 + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) 16 + }
+7
build-logic/settings.gradle.kts
··· 1 + dependencyResolutionManagement { 2 + versionCatalogs { 3 + create("libs") { 4 + from(files("../gradle/libs.versions.toml")) 5 + } 6 + } 7 + }
+42
build-logic/src/main/kotlin/base-conventions.gradle.kts
··· 1 + plugins { 2 + idea 3 + id("net.kyori.indra") 4 + id("net.kyori.indra.checkstyle") 5 + id("net.kyori.indra.licenser.spotless") 6 + } 7 + 8 + version = rootProject.version 9 + 10 + indra { 11 + gpl3OrLaterLicense() 12 + 13 + javaVersions { 14 + target(25) 15 + } 16 + } 17 + 18 + indraSpotlessLicenser { 19 + licenseHeaderFile(rootProject.file("license_header.txt")) 20 + } 21 + 22 + dependencies { 23 + checkstyle(libs.stylecheck) 24 + testImplementation(libs.junit.jupiter) 25 + testRuntimeOnly(libs.junit.platform.launcher) 26 + } 27 + 28 + tasks { 29 + jar { 30 + dependsOn(check) 31 + } 32 + test { 33 + useJUnitPlatform() 34 + } 35 + } 36 + 37 + idea { 38 + module { 39 + isDownloadJavadoc = true 40 + isDownloadSources = true 41 + } 42 + }
+17
build-logic/src/main/kotlin/extensions.kt
··· 1 + import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 + import org.gradle.accessors.dm.LibrariesForLibs 3 + import org.gradle.api.Project 4 + import org.gradle.kotlin.dsl.the 5 + 6 + // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 7 + val Project.libs: LibrariesForLibs 8 + get() = the() 9 + 10 + /** 11 + * Relocate a package into a project-scoped namespace. 12 + */ 13 + fun ShadowJar.relocateDependency(pkg: String) { 14 + val groupId = project.group.toString().ifBlank { "com.example" } 15 + val projectId = project.name.ifBlank { "template" } 16 + relocate(pkg, "$groupId.$projectId.libs.$pkg") 17 + }
+29
build-logic/src/main/kotlin/publishing-conventions.gradle.kts
··· 1 + plugins { 2 + id("base-conventions") 3 + `maven-publish` 4 + } 5 + 6 + tasks { 7 + javadoc { 8 + dependsOn(check) 9 + options { 10 + (this as StandardJavadocDocletOptions).apply { 11 + encoding = Charsets.UTF_8.name() 12 + links( 13 + "https://docs.oracle.com/en/java/javase/25/docs/api/", 14 + ) 15 + } 16 + } 17 + } 18 + } 19 + 20 + configure<PublishingExtension> { 21 + publications { 22 + register<MavenPublication>("maven") { 23 + from(components["java"]) 24 + } 25 + } 26 + repositories { 27 + mavenLocal() 28 + } 29 + }
+2
build.gradle.kts
··· 1 + group = "com.example" 2 + version = "1.0.0"
+21
gradle/libs.versions.toml
··· 1 + [versions] 2 + indra = "4.0.0" 3 + stylecheck = "0.2.1" 4 + shadow = "9.3.1" 5 + junit = "6.0.2" 6 + jspecify = "1.0.0" 7 + 8 + [libraries] 9 + # build logic 10 + indra-common = { group = "net.kyori", name = "indra-common", version.ref = "indra" } 11 + indra-licenseHeader = { group = "net.kyori", name = "indra-licenser-spotless", version.ref = "indra" } 12 + shadow = { group = "com.gradleup.shadow", name = "shadow-gradle-plugin", version.ref = "shadow" } 13 + 14 + # development tools (code quality, annotations) 15 + stylecheck = { group = "ca.stellardrift", name = "stylecheck", version.ref = "stylecheck" } 16 + jspecify = { group = "org.jspecify", name = "jspecify", version.ref = "jspecify" } 17 + 18 + # testing 19 + junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } 20 + junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" } 21 +
gradle/wrapper/gradle-wrapper.jar

This is a binary file and will not be displayed.

+7
gradle/wrapper/gradle-wrapper.properties
··· 1 + distributionBase=GRADLE_USER_HOME 2 + distributionPath=wrapper/dists 3 + distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip 4 + networkTimeout=10000 5 + validateDistributionUrl=true 6 + zipStoreBase=GRADLE_USER_HOME 7 + zipStorePath=wrapper/dists
+248
gradlew
··· 1 + #!/bin/sh 2 + 3 + # 4 + # Copyright © 2015 the original authors. 5 + # 6 + # Licensed under the Apache License, Version 2.0 (the "License"); 7 + # you may not use this file except in compliance with the License. 8 + # You may obtain a copy of the License at 9 + # 10 + # https://www.apache.org/licenses/LICENSE-2.0 11 + # 12 + # Unless required by applicable law or agreed to in writing, software 13 + # distributed under the License is distributed on an "AS IS" BASIS, 14 + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + # See the License for the specific language governing permissions and 16 + # limitations under the License. 17 + # 18 + # SPDX-License-Identifier: Apache-2.0 19 + # 20 + 21 + ############################################################################## 22 + # 23 + # Gradle start up script for POSIX generated by Gradle. 24 + # 25 + # Important for running: 26 + # 27 + # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 + # noncompliant, but you have some other compliant shell such as ksh or 29 + # bash, then to run this script, type that shell name before the whole 30 + # command line, like: 31 + # 32 + # ksh Gradle 33 + # 34 + # Busybox and similar reduced shells will NOT work, because this script 35 + # requires all of these POSIX shell features: 36 + # * functions; 37 + # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 + # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 + # * compound commands having a testable exit status, especially «case»; 40 + # * various built-in commands including «command», «set», and «ulimit». 41 + # 42 + # Important for patching: 43 + # 44 + # (2) This script targets any POSIX shell, so it avoids extensions provided 45 + # by Bash, Ksh, etc; in particular arrays are avoided. 46 + # 47 + # The "traditional" practice of packing multiple parameters into a 48 + # space-separated string is a well documented source of bugs and security 49 + # problems, so this is (mostly) avoided, by progressively accumulating 50 + # options in "$@", and eventually passing that to Java. 51 + # 52 + # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 + # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 + # see the in-line comments for details. 55 + # 56 + # There are tweaks for specific operating systems such as AIX, CygWin, 57 + # Darwin, MinGW, and NonStop. 58 + # 59 + # (3) This script is generated from the Groovy template 60 + # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 + # within the Gradle project. 62 + # 63 + # You can find Gradle at https://github.com/gradle/gradle/. 64 + # 65 + ############################################################################## 66 + 67 + # Attempt to set APP_HOME 68 + 69 + # Resolve links: $0 may be a link 70 + app_path=$0 71 + 72 + # Need this for daisy-chained symlinks. 73 + while 74 + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 + [ -h "$app_path" ] 76 + do 77 + ls=$( ls -ld "$app_path" ) 78 + link=${ls#*' -> '} 79 + case $link in #( 80 + /*) app_path=$link ;; #( 81 + *) app_path=$APP_HOME$link ;; 82 + esac 83 + done 84 + 85 + # This is normally unused 86 + # shellcheck disable=SC2034 87 + APP_BASE_NAME=${0##*/} 88 + # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 + APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 + 91 + # Use the maximum available, or set MAX_FD != -1 to use that value. 92 + MAX_FD=maximum 93 + 94 + warn () { 95 + echo "$*" 96 + } >&2 97 + 98 + die () { 99 + echo 100 + echo "$*" 101 + echo 102 + exit 1 103 + } >&2 104 + 105 + # OS specific support (must be 'true' or 'false'). 106 + cygwin=false 107 + msys=false 108 + darwin=false 109 + nonstop=false 110 + case "$( uname )" in #( 111 + CYGWIN* ) cygwin=true ;; #( 112 + Darwin* ) darwin=true ;; #( 113 + MSYS* | MINGW* ) msys=true ;; #( 114 + NONSTOP* ) nonstop=true ;; 115 + esac 116 + 117 + 118 + 119 + # Determine the Java command to use to start the JVM. 120 + if [ -n "$JAVA_HOME" ] ; then 121 + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 122 + # IBM's JDK on AIX uses strange locations for the executables 123 + JAVACMD=$JAVA_HOME/jre/sh/java 124 + else 125 + JAVACMD=$JAVA_HOME/bin/java 126 + fi 127 + if [ ! -x "$JAVACMD" ] ; then 128 + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 129 + 130 + Please set the JAVA_HOME variable in your environment to match the 131 + location of your Java installation." 132 + fi 133 + else 134 + JAVACMD=java 135 + if ! command -v java >/dev/null 2>&1 136 + then 137 + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 138 + 139 + Please set the JAVA_HOME variable in your environment to match the 140 + location of your Java installation." 141 + fi 142 + fi 143 + 144 + # Increase the maximum file descriptors if we can. 145 + if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 146 + case $MAX_FD in #( 147 + max*) 148 + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 149 + # shellcheck disable=SC2039,SC3045 150 + MAX_FD=$( ulimit -H -n ) || 151 + warn "Could not query maximum file descriptor limit" 152 + esac 153 + case $MAX_FD in #( 154 + '' | soft) :;; #( 155 + *) 156 + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 157 + # shellcheck disable=SC2039,SC3045 158 + ulimit -n "$MAX_FD" || 159 + warn "Could not set maximum file descriptor limit to $MAX_FD" 160 + esac 161 + fi 162 + 163 + # Collect all arguments for the java command, stacking in reverse order: 164 + # * args from the command line 165 + # * the main class name 166 + # * -classpath 167 + # * -D...appname settings 168 + # * --module-path (only if needed) 169 + # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 170 + 171 + # For Cygwin or MSYS, switch paths to Windows format before running java 172 + if "$cygwin" || "$msys" ; then 173 + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 174 + 175 + JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 + 177 + # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 + for arg do 179 + if 180 + case $arg in #( 181 + -*) false ;; # don't mess with options #( 182 + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 + [ -e "$t" ] ;; #( 184 + *) false ;; 185 + esac 186 + then 187 + arg=$( cygpath --path --ignore --mixed "$arg" ) 188 + fi 189 + # Roll the args list around exactly as many times as the number of 190 + # args, so each arg winds up back in the position where it started, but 191 + # possibly modified. 192 + # 193 + # NB: a `for` loop captures its iteration list before it begins, so 194 + # changing the positional parameters here affects neither the number of 195 + # iterations, nor the values presented in `arg`. 196 + shift # remove old arg 197 + set -- "$@" "$arg" # push replacement arg 198 + done 199 + fi 200 + 201 + 202 + # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 + DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 + 205 + # Collect all arguments for the java command: 206 + # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 + # and any embedded shellness will be escaped. 208 + # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 + # treated as '${Hostname}' itself on the command line. 210 + 211 + set -- \ 212 + "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 214 + "$@" 215 + 216 + # Stop when "xargs" is not available. 217 + if ! command -v xargs >/dev/null 2>&1 218 + then 219 + die "xargs is not available" 220 + fi 221 + 222 + # Use "xargs" to parse quoted args. 223 + # 224 + # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 + # 226 + # In Bash we could simply go: 227 + # 228 + # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 + # set -- "${ARGS[@]}" "$@" 230 + # 231 + # but POSIX shell has neither arrays nor command substitution, so instead we 232 + # post-process each arg (as a line of input to sed) to backslash-escape any 233 + # character that might be a shell metacharacter, then use eval to reverse 234 + # that process (while maintaining the separation between arguments), and wrap 235 + # the whole thing up as a single "set" statement. 236 + # 237 + # This will of course break if any of these variables contains a newline or 238 + # an unmatched quote. 239 + # 240 + 241 + eval "set -- $( 242 + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 + xargs -n1 | 244 + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 + tr '\n' ' ' 246 + )" '"$@"' 247 + 248 + exec "$JAVACMD" "$@"
+93
gradlew.bat
··· 1 + @rem 2 + @rem Copyright 2015 the original author or authors. 3 + @rem 4 + @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 + @rem you may not use this file except in compliance with the License. 6 + @rem You may obtain a copy of the License at 7 + @rem 8 + @rem https://www.apache.org/licenses/LICENSE-2.0 9 + @rem 10 + @rem Unless required by applicable law or agreed to in writing, software 11 + @rem distributed under the License is distributed on an "AS IS" BASIS, 12 + @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 + @rem See the License for the specific language governing permissions and 14 + @rem limitations under the License. 15 + @rem 16 + @rem SPDX-License-Identifier: Apache-2.0 17 + @rem 18 + 19 + @if "%DEBUG%"=="" @echo off 20 + @rem ########################################################################## 21 + @rem 22 + @rem Gradle startup script for Windows 23 + @rem 24 + @rem ########################################################################## 25 + 26 + @rem Set local scope for the variables with windows NT shell 27 + if "%OS%"=="Windows_NT" setlocal 28 + 29 + set DIRNAME=%~dp0 30 + if "%DIRNAME%"=="" set DIRNAME=. 31 + @rem This is normally unused 32 + set APP_BASE_NAME=%~n0 33 + set APP_HOME=%DIRNAME% 34 + 35 + @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 + for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 + 38 + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 + set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 + 41 + @rem Find java.exe 42 + if defined JAVA_HOME goto findJavaFromJavaHome 43 + 44 + set JAVA_EXE=java.exe 45 + %JAVA_EXE% -version >NUL 2>&1 46 + if %ERRORLEVEL% equ 0 goto execute 47 + 48 + echo. 1>&2 49 + echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 + echo. 1>&2 51 + echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 + echo location of your Java installation. 1>&2 53 + 54 + goto fail 55 + 56 + :findJavaFromJavaHome 57 + set JAVA_HOME=%JAVA_HOME:"=% 58 + set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 + 60 + if exist "%JAVA_EXE%" goto execute 61 + 62 + echo. 1>&2 63 + echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 + echo. 1>&2 65 + echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 + echo location of your Java installation. 1>&2 67 + 68 + goto fail 69 + 70 + :execute 71 + @rem Setup the command line 72 + 73 + 74 + 75 + @rem Execute Gradle 76 + "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 + 78 + :end 79 + @rem End local scope for the variables with windows NT shell 80 + if %ERRORLEVEL% equ 0 goto mainEnd 81 + 82 + :fail 83 + rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 + rem the _cmd.exe /c_ return code! 85 + set EXIT_CODE=%ERRORLEVEL% 86 + if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 + if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 + exit /b %EXIT_CODE% 89 + 90 + :mainEnd 91 + if "%OS%"=="Windows_NT" endlocal 92 + 93 + :omega
+21
license.txt
··· 1 + MIT License 2 + 3 + Copyright (c) 2026 nayrid 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+21
license_header.txt
··· 1 + This file is part of <project name>, licensed under the MIT License. 2 + 3 + Copyright (c) 2026 nayrid 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+23
readme.md
··· 1 + # template 2 + 3 + This template is marked [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/). 4 + 5 + The `license.txt` and `license_header.txt` this template provides are MIT. You will want to change 6 + them if your project will be released under a different license. 7 + 8 + ## Quick start 9 + 10 + Run the rename script to set your group, project name, and Java package: 11 + 12 + ```bash 13 + ./.scripts/rename-template.sh -g "com.acme" -p "my-project" 14 + ``` 15 + 16 + ## Checkstyle 17 + 18 + This template uses a fork of checkstyle. For checkstyle support in IntelliJ IDEA: 19 + 20 + 1. Install the checkstyle plugin. 21 + 2. Compile stylecheck from [its repository](https://codeberg.org/stellardrift/stylecheck). 22 + 3. In `Settings` -> `Tools` -> `Checkstyle` `Third-Party Checks`, add the compiled stylecheck jar. 23 + 4. In the `Checkstyle` tab, set the configuration file to `.checkstyle/checkstyle.xml`.
+18
settings.gradle.kts
··· 1 + dependencyResolutionManagement { 2 + @Suppress("UnstableApiUsage") 3 + repositories { 4 + mavenCentral() 5 + } 6 + } 7 + 8 + pluginManagement { 9 + repositories { 10 + gradlePluginPortal() 11 + } 12 + includeBuild("build-logic") 13 + } 14 + 15 + rootProject.name = "template" 16 + 17 + include("api") 18 + project(":api").projectDir = file("api")