├── .editorconfig
├── .github
└── workflows
│ ├── gradle-nebula.yml
│ └── maven.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── mvnw
├── mvnw.cmd
├── pom.xml
├── scripts
├── check-release.sh
├── deploy-latest.sh
└── tag-release.sh
├── settings.gradle
└── src
├── main
├── java
│ └── com
│ │ └── droidablebee
│ │ └── springboot
│ │ └── rest
│ │ ├── Application.java
│ │ ├── config
│ │ ├── AuthorizationConfiguration.java
│ │ ├── WebConfiguration.java
│ │ └── WebSecurityConfig.java
│ │ ├── domain
│ │ ├── Address.java
│ │ └── Person.java
│ │ ├── endpoint
│ │ ├── BaseEndpoint.java
│ │ ├── CustomActuatorEndpoint.java
│ │ ├── InfoWebEndpointExtension.java
│ │ ├── PersonEndpoint.java
│ │ ├── PersonValidator.java
│ │ └── error
│ │ │ └── Error.java
│ │ ├── repository
│ │ └── PersonRepository.java
│ │ └── service
│ │ ├── CacheableService.java
│ │ └── PersonService.java
└── resources
│ ├── application.yml
│ ├── logback.xml
│ └── messages.properties
└── test
├── groovy
└── com
│ └── droidablebee
│ └── springboot
│ └── rest
│ ├── ApplicationSpec.groovy
│ ├── endpoint
│ ├── ActuatorEndpointSpec.groovy
│ ├── ActuatorEndpointStubbedSpec.groovy
│ ├── BaseEndpointSpec.groovy
│ ├── PersonEndpointAuthorizationDisabledSpec.groovy
│ ├── PersonEndpointSpec.groovy
│ ├── PersonEndpointStubbedSpec.groovy
│ └── SwaggerEndpointSpec.groovy
│ ├── repository
│ └── PersonRepositorySpec.groovy
│ └── service
│ └── CacheableServiceSpec.groovy
├── java
└── com
│ └── droidablebee
│ └── springboot
│ └── rest
│ ├── endpoint
│ ├── ActuatorEndpointStubbedTest.java
│ ├── ActuatorEndpointTest.java
│ ├── BaseEndpointTest.java
│ ├── PersonEndpointStubbedTest.java
│ ├── PersonEndpointTest.java
│ └── SwaggerEndpointTest.java
│ └── repository
│ └── PersonRepositoryTest.java
└── resources
├── application-default.yml
└── logback-test.xml
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 | end_of_line = lf
8 | indent_style = space
9 | indent_size = 4
10 |
11 | # 2 space indentation
12 | [*.{xml,html,json,y*ml}]
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.github/workflows/gradle-nebula.yml:
--------------------------------------------------------------------------------
1 | name: Java CI using Gradle and Nebula
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - release/*
8 | pull_request:
9 | branches:
10 | - master
11 | - release/*
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 | # The GITHUB_TOKEN secret is set to an access token for the repository each time a job in a workflow begins.
17 | # You should set the permissions for this access token in the workflow file to grant
18 | # read access for the contents scope and write access for the packages scope.
19 | permissions:
20 | contents: write
21 | packages: write
22 | pull-requests: write
23 | checks: write
24 |
25 | steps:
26 | - uses: actions/checkout@v4
27 | with:
28 | # 0 indicates all history for all branches and tags
29 | fetch-depth: "0"
30 |
31 | - name: Set up JDK 17
32 | uses: actions/setup-java@v4
33 | with:
34 | java-version: 17
35 | distribution: 'temurin'
36 | settings-path: ${{ github.workspace }} # location for the settings.xml file
37 |
38 | - name: Setup Gradle
39 | uses: gradle/actions/setup-gradle@v4
40 |
41 | - name: git status
42 | run: |
43 | git status
44 | git remote -v
45 |
46 | - name: Build for PR
47 | if: github.event_name == 'pull_request'
48 | run: ./gradlew build -Prelease.stage=final
49 |
50 | - name: Add test report to PR checks
51 | uses: dorny/test-reporter@v1
52 | if: (success() || failure()) && github.event_name == 'pull_request'
53 | with:
54 | name: Tests report
55 | path: ${{ github.workspace }}/build/test-results/test/*.xml
56 | reporter: java-junit
57 |
58 | - name: Add code coverage to PR
59 | id: jacoco
60 | uses: madrapps/jacoco-report@v1.5
61 | if: github.event_name == 'pull_request'
62 | with:
63 | paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml
64 | token: ${{ secrets.GITHUB_TOKEN }}
65 | min-coverage-overall: 90
66 | min-coverage-changed-files: 99
67 |
68 | - name: Build, publish and tag release
69 | if: github.event_name == 'push'
70 | run: ./gradlew build publish final -Prelease.stage=final
71 | env:
72 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73 |
74 | # upload full test report (e.g. in case stdout / stderr is needed)
75 | - name: Upload test report
76 | uses: actions/upload-artifact@v4
77 | if: success() || failure()
78 | with:
79 | name: Tests report
80 | path: ${{ github.workspace }}/build/reports/tests
81 | retention-days: 1
82 |
83 | - name: deploy new release
84 | if: github.event_name == 'push'
85 | run: scripts/deploy-latest.sh
86 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java Maven CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - release/*
8 | pull_request:
9 | branches:
10 | - master
11 | - release/*
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | # 0 indicates all history for all branches and tags
21 | fetch-depth: "0"
22 | - name: Set up JDK 11
23 | uses: actions/setup-java@v1
24 | with:
25 | java-version: 11
26 |
27 | - name: git status
28 | run: |
29 | git status
30 | git remote -v
31 |
32 | - name: check release tag
33 | if: github.event_name == 'pull_request'
34 | run: scripts/check-release.sh
35 |
36 | - name: Build with Maven
37 | run: mvn -B package --file pom.xml
38 |
39 | - name: tag release
40 | if: github.event_name == 'push'
41 | run: scripts/tag-release.sh
42 |
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | bin
3 | .settings
4 | .classpath
5 | .project
6 | .idea
7 | *.iml
8 |
9 | build
10 | .gradle
11 |
12 | # github workflow
13 | settings.xml
14 | toolchains.xml
15 |
16 | # Mac
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pavelfomin/spring-boot-rest-example/6409ae7fa7c124cd829ef1ceb7c20e9a25c99876/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring boot example with REST and spring data JPA
2 | See [micronaut-rest-example](https://github.com/pavelfomin/micronaut-rest-example) for `Micronaut` implementation.
3 |
4 | ### Running tests
5 | * Maven: `./mvnw clean test`
6 | * Gradle: `./gradlew clean test`
7 |
8 | ### Endpoints
9 |
10 | | Method | Url | Decription |
11 | | ------ | --- | ---------- |
12 | | GET |/actuator/info | info / heartbeat - provided by boot |
13 | | GET |/actuator/health| application health - provided by boot |
14 | | GET |/v2/api-docs | swagger json |
15 | | GET |/swagger-ui.html| swagger html |
16 | | GET |/v1/person/{id}| get person by id |
17 | | GET |/v1/persons | get N persons with an offset|
18 | | PUT |/v1/person | add / update person|
19 |
20 | ### Change maven version
21 | `mvn -N io.takari:maven:wrapper -Dmaven=3.8.4`
22 |
23 | ### Upgrade Gradle
24 | * ./gradlew wrapper --gradle-version 8.11
25 | * ./gradlew wrapper
26 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.springframework.boot' version '3.4.3'
3 | id 'io.spring.dependency-management' version '1.1.7'
4 | id 'java'
5 | id 'groovy'
6 | id 'nebula.release' version "17.1.0"
7 | id 'nebula.maven-publish' version "18.4.0"
8 | id 'jacoco'
9 | id 'maven-publish'
10 | }
11 |
12 | java {
13 | sourceCompatibility = '17'
14 | withJavadocJar()
15 | withSourcesJar()
16 | }
17 |
18 | springBoot {
19 | buildInfo()
20 | }
21 |
22 | ext {
23 | springDocVersion = '2.3.0'
24 | spockVersion = '2.4-M4-groovy-4.0'
25 | }
26 |
27 | dependencies {
28 | implementation "org.springframework.boot:spring-boot-starter-web"
29 | implementation "org.springframework.boot:spring-boot-starter-actuator"
30 | implementation "org.springframework.boot:spring-boot-starter-validation"
31 | implementation "org.springframework.boot:spring-boot-starter-data-jpa"
32 | implementation "org.springframework.boot:spring-boot-starter-security"
33 | implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server"
34 | // implementation 'org.springframework.boot:spring-boot-starter-cache'
35 | implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:${springDocVersion}"
36 |
37 | implementation "com.h2database:h2:2.1.210"
38 | // implementation 'com.github.ben-manes.caffeine:caffeine'
39 |
40 | testImplementation ("org.springframework.boot:spring-boot-starter-test") {
41 | // exclude group: 'org.mockito'
42 | // exclude group: 'org.junit.jupiter'
43 | }
44 | testImplementation "org.springframework.security:spring-security-test"
45 | testImplementation platform("org.spockframework:spock-bom:${spockVersion}")
46 | testImplementation "org.spockframework:spock-spring"
47 | testImplementation "org.apache.groovy:groovy-json"
48 | }
49 |
50 | repositories {
51 | mavenLocal()
52 | mavenCentral()
53 | }
54 |
55 | tasks.named('test') {
56 | useJUnitPlatform()
57 | testLogging {
58 | events "passed", "skipped", "failed"
59 | }
60 | afterSuite { desc, result ->
61 | if (!desc.parent)
62 | println("${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)")
63 | }
64 | finalizedBy jacocoTestReport // report is always generated after tests run
65 | }
66 |
67 | jacocoTestReport {
68 | dependsOn test // tests are required to run before generating the report
69 | reports {
70 | xml.required = true
71 | }
72 | }
73 |
74 | publishing {
75 | repositories {
76 | maven {
77 | name = "GitHubPackages"
78 | url = "https://maven.pkg.github.com/pavelfomin/spring-boot-rest-example"
79 | credentials {
80 | username = System.getenv("GITHUB_ACTOR")
81 | password = System.getenv("GITHUB_TOKEN")
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | group=com.droidablebee
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pavelfomin/spring-boot-rest-example/6409ae7fa7c124cd829ef1ceb7c20e9a25c99876/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 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
90 | ' "$PWD" ) || exit
91 |
92 | # Use the maximum available, or set MAX_FD != -1 to use that value.
93 | MAX_FD=maximum
94 |
95 | warn () {
96 | echo "$*"
97 | } >&2
98 |
99 | die () {
100 | echo
101 | echo "$*"
102 | echo
103 | exit 1
104 | } >&2
105 |
106 | # OS specific support (must be 'true' or 'false').
107 | cygwin=false
108 | msys=false
109 | darwin=false
110 | nonstop=false
111 | case "$( uname )" in #(
112 | CYGWIN* ) cygwin=true ;; #(
113 | Darwin* ) darwin=true ;; #(
114 | MSYS* | MINGW* ) msys=true ;; #(
115 | NONSTOP* ) nonstop=true ;;
116 | esac
117 |
118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
119 |
120 |
121 | # Determine the Java command to use to start the JVM.
122 | if [ -n "$JAVA_HOME" ] ; then
123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
124 | # IBM's JDK on AIX uses strange locations for the executables
125 | JAVACMD=$JAVA_HOME/jre/sh/java
126 | else
127 | JAVACMD=$JAVA_HOME/bin/java
128 | fi
129 | if [ ! -x "$JAVACMD" ] ; then
130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
131 |
132 | Please set the JAVA_HOME variable in your environment to match the
133 | location of your Java installation."
134 | fi
135 | else
136 | JAVACMD=java
137 | if ! command -v java >/dev/null 2>&1
138 | then
139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
140 |
141 | Please set the JAVA_HOME variable in your environment to match the
142 | location of your Java installation."
143 | fi
144 | fi
145 |
146 | # Increase the maximum file descriptors if we can.
147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
148 | case $MAX_FD in #(
149 | max*)
150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
151 | # shellcheck disable=SC2039,SC3045
152 | MAX_FD=$( ulimit -H -n ) ||
153 | warn "Could not query maximum file descriptor limit"
154 | esac
155 | case $MAX_FD in #(
156 | '' | soft) :;; #(
157 | *)
158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
159 | # shellcheck disable=SC2039,SC3045
160 | ulimit -n "$MAX_FD" ||
161 | warn "Could not set maximum file descriptor limit to $MAX_FD"
162 | esac
163 | fi
164 |
165 | # Collect all arguments for the java command, stacking in reverse order:
166 | # * args from the command line
167 | # * the main class name
168 | # * -classpath
169 | # * -D...appname settings
170 | # * --module-path (only if needed)
171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
172 |
173 | # For Cygwin or MSYS, switch paths to Windows format before running java
174 | if "$cygwin" || "$msys" ; then
175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
177 |
178 | JAVACMD=$( cygpath --unix "$JAVACMD" )
179 |
180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
181 | for arg do
182 | if
183 | case $arg in #(
184 | -*) false ;; # don't mess with options #(
185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
186 | [ -e "$t" ] ;; #(
187 | *) false ;;
188 | esac
189 | then
190 | arg=$( cygpath --path --ignore --mixed "$arg" )
191 | fi
192 | # Roll the args list around exactly as many times as the number of
193 | # args, so each arg winds up back in the position where it started, but
194 | # possibly modified.
195 | #
196 | # NB: a `for` loop captures its iteration list before it begins, so
197 | # changing the positional parameters here affects neither the number of
198 | # iterations, nor the values presented in `arg`.
199 | shift # remove old arg
200 | set -- "$@" "$arg" # push replacement arg
201 | done
202 | fi
203 |
204 |
205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
207 |
208 | # Collect all arguments for the java command:
209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
210 | # and any embedded shellness will be escaped.
211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
212 | # treated as '${Hostname}' itself on the command line.
213 |
214 | set -- \
215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
216 | -classpath "$CLASSPATH" \
217 | org.gradle.wrapper.GradleWrapperMain \
218 | "$@"
219 |
220 | # Stop when "xargs" is not available.
221 | if ! command -v xargs >/dev/null 2>&1
222 | then
223 | die "xargs is not available"
224 | fi
225 |
226 | # Use "xargs" to parse quoted args.
227 | #
228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
229 | #
230 | # In Bash we could simply go:
231 | #
232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
233 | # set -- "${ARGS[@]}" "$@"
234 | #
235 | # but POSIX shell has neither arrays nor command substitution, so instead we
236 | # post-process each arg (as a line of input to sed) to backslash-escape any
237 | # character that might be a shell metacharacter, then use eval to reverse
238 | # that process (while maintaining the separation between arguments), and wrap
239 | # the whole thing up as a single "set" statement.
240 | #
241 | # This will of course break if any of these variables contains a newline or
242 | # an unmatched quote.
243 | #
244 |
245 | eval "set -- $(
246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
247 | xargs -n1 |
248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
249 | tr '\n' ' '
250 | )" '"$@"'
251 |
252 | exec "$JAVACMD" "$@"
253 |
--------------------------------------------------------------------------------
/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 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.droidablebee
6 | spring-boot-rest-example
7 | 2.6.3.0
8 | Spring boot example with REST and spring data JPA
9 |
10 | jar
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.6.3
16 |
17 |
18 |
19 | 11
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-web
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-validation
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-data-jpa
36 |
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-starter-actuator
42 |
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-oauth2-resource-server
48 |
49 |
50 |
51 |
52 | com.fasterxml.jackson.dataformat
53 | jackson-dataformat-xml
54 | 2.9.4
55 |
56 |
57 |
58 |
59 | org.springdoc
60 | springdoc-openapi-ui
61 | 1.6.5
62 |
63 |
64 |
65 |
66 | com.h2database
67 | h2
68 | 2.2.220
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-starter-test
75 | test
76 |
77 |
78 |
79 | org.springframework.security
80 | spring-security-test
81 | test
82 |
83 |
84 |
85 |
86 |
87 |
88 | org.apache.maven.plugins
89 | maven-compiler-plugin
90 |
91 | ${java.version}
92 | ${java.version}
93 |
94 |
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-maven-plugin
99 |
100 |
101 |
102 | build-info
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/scripts/check-release.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | version=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
3 | echo "Checking that release tag $version does not exist"
4 | git tag -l | grep $version
5 | [ $? == 1 ] || exit 1
6 |
--------------------------------------------------------------------------------
/scripts/deploy-latest.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | version=$(git describe --abbrev=0 --tags)
3 | echo "Deploying version: $version"
4 | #todo: deployment steps here
--------------------------------------------------------------------------------
/scripts/tag-release.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | version=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
3 | echo "Creating release tag $version"
4 | git tag $version
5 | git push --tags
6 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | // https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories
2 | //pluginManagement {
3 | // repositories {
4 | // maven {
5 | // url 'https://artifactory.droidablebee.com/artifactory/plugins-release'
6 | // credentials {
7 | // username = artifactoryUsername
8 | // password = artifactoryPassword
9 | // }
10 | // }
11 | // }
12 | //}
13 |
14 | rootProject.name = 'spring-boot-rest-example'
15 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/Application.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.cache.annotation.EnableCaching;
8 |
9 | @SpringBootApplication
10 | @EnableCaching
11 | public class Application {
12 | @SuppressWarnings("unused")
13 | private static final Logger log = LoggerFactory.getLogger(Application.class);
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(Application.class);
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/config/AuthorizationConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.config;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component
7 | public class AuthorizationConfiguration {
8 |
9 | @Value("${app.authorization.enabled:true}")
10 | private boolean enabled;
11 |
12 | public boolean isEnabled() {
13 | return enabled;
14 | }
15 |
16 | public boolean isDisabled() {
17 | return !enabled;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/config/WebConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.MediaType;
6 | import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
7 | import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9 |
10 | @Configuration
11 | public class WebConfiguration implements WebMvcConfigurer {
12 |
13 | @Override
14 | public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
15 | configurer.defaultContentType(MediaType.APPLICATION_JSON);
16 | }
17 |
18 | /**
19 | * Enable @Valid validation exception handler for @PathVariable, @RequestParam and @RequestHeader.
20 | */
21 | @Bean
22 | public MethodValidationPostProcessor methodValidationPostProcessor() {
23 | return new MethodValidationPostProcessor();
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.config;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.security.config.Customizer;
7 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
11 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
12 | import org.springframework.security.config.http.SessionCreationPolicy;
13 | import org.springframework.security.web.SecurityFilterChain;
14 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
15 |
16 | @Configuration
17 | @EnableWebSecurity
18 | @EnableMethodSecurity
19 | public class WebSecurityConfig {
20 |
21 | @Value("${app.security.ignore:/swagger/**, /swagger-resources/**, /swagger-ui/**, /swagger-ui.html, /webjars/**, /v3/api-docs/**, /actuator/info}")
22 | private String[] ignorePatterns;
23 |
24 | @Bean
25 | public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
26 |
27 | http
28 | .csrf(AbstractHttpConfigurer::disable)
29 | .authorizeHttpRequests(customizer -> customizer
30 | //make sure principal is created for the health endpoint to verify the role
31 | .requestMatchers(new AntPathRequestMatcher("/actuator/health"))
32 | .permitAll()
33 | .anyRequest()
34 | .authenticated()
35 | )
36 | .oauth2ResourceServer((configurer) -> configurer.jwt(Customizer.withDefaults()))
37 | .sessionManagement((s) -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
38 |
39 | return http.build();
40 | }
41 |
42 | @Bean
43 | public WebSecurityCustomizer webSecurityCustomizer() {
44 |
45 | return (web) -> web.ignoring().requestMatchers(ignorePatterns);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/domain/Address.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.domain;
2 |
3 | import jakarta.persistence.Column;
4 | import jakarta.persistence.Entity;
5 | import jakarta.persistence.GeneratedValue;
6 | import jakarta.persistence.GenerationType;
7 | import jakarta.persistence.Id;
8 | import jakarta.validation.constraints.NotNull;
9 |
10 | @Entity
11 | public class Address {
12 |
13 | @Id
14 | @GeneratedValue(strategy = GenerationType.AUTO)
15 | @Column(name = "address_id")
16 | private Long id;
17 |
18 | @NotNull
19 | private String line1;
20 | private String line2;
21 | @NotNull
22 | private String city;
23 | @NotNull
24 | private String state;
25 | @NotNull
26 | private String zip;
27 |
28 | public Address() {
29 | }
30 |
31 | public Address(String line1, String city, String state, String zip) {
32 |
33 | this.line1 = line1;
34 | this.city = city;
35 | this.state = state;
36 | this.zip = zip;
37 | }
38 |
39 | public Long getId() {
40 | return id;
41 | }
42 |
43 | public String getLine1() {
44 | return line1;
45 | }
46 |
47 | public void setLine1(String line1) {
48 | this.line1 = line1;
49 | }
50 |
51 | public String getLine2() {
52 | return line2;
53 | }
54 |
55 | public void setLine2(String line2) {
56 | this.line2 = line2;
57 | }
58 |
59 | public String getCity() {
60 | return city;
61 | }
62 |
63 | public void setCity(String city) {
64 | this.city = city;
65 | }
66 |
67 | public String getState() {
68 | return state;
69 | }
70 |
71 | public void setState(String state) {
72 | this.state = state;
73 | }
74 |
75 | public String getZip() {
76 | return zip;
77 | }
78 |
79 | public void setZip(String zip) {
80 | this.zip = zip;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/domain/Person.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.domain;
2 |
3 | import jakarta.persistence.CascadeType;
4 | import jakarta.persistence.Column;
5 | import jakarta.persistence.Entity;
6 | import jakarta.persistence.GeneratedValue;
7 | import jakarta.persistence.GenerationType;
8 | import jakarta.persistence.Id;
9 | import jakarta.persistence.JoinColumn;
10 | import jakarta.persistence.OneToMany;
11 | import jakarta.validation.Valid;
12 | import jakarta.validation.constraints.NotNull;
13 |
14 | import java.util.Date;
15 | import java.util.HashSet;
16 | import java.util.Set;
17 |
18 | @Entity
19 | public class Person {
20 |
21 | @Id
22 | @GeneratedValue(strategy = GenerationType.AUTO)
23 | @Column(name = "person_id")
24 | private Long id;
25 |
26 | @NotNull
27 | @Column(name = "first_name", nullable = false)
28 | private String firstName;
29 |
30 | @NotNull
31 | @Column(name = "last_name", nullable = false)
32 | private String lastName;
33 |
34 | @Column(name = "middle_name")
35 | private String middleName;
36 |
37 | @Column(name = "dob")
38 | private Date dateOfBirth;
39 |
40 | @Column(name = "gender")
41 | private Gender gender;
42 |
43 | @Valid
44 | @OneToMany(cascade = CascadeType.ALL)
45 | @JoinColumn(name = "person_id")
46 | private Set
addresses;
47 |
48 | protected Person() {
49 | }
50 |
51 | public Person(Long id, String firstName, String lastName) {
52 | this.id = id;
53 | this.firstName = firstName;
54 | this.lastName = lastName;
55 | }
56 |
57 | public Person(String firstName, String lastName) {
58 | this.firstName = firstName;
59 | this.lastName = lastName;
60 | }
61 |
62 | public Long getId() {
63 | return id;
64 | }
65 |
66 | public String getFirstName() {
67 | return firstName;
68 | }
69 |
70 | public void setFirstName(String firstName) {
71 | this.firstName = firstName;
72 | }
73 |
74 | public String getLastName() {
75 | return lastName;
76 | }
77 |
78 | public void setLastName(String lastName) {
79 | this.lastName = lastName;
80 | }
81 |
82 | public String getMiddleName() {
83 | return middleName;
84 | }
85 |
86 | public void setMiddleName(String middleName) {
87 | this.middleName = middleName;
88 | }
89 |
90 | public Date getDateOfBirth() {
91 | return dateOfBirth;
92 | }
93 |
94 | public void setDateOfBirth(Date dateOfBirth) {
95 | this.dateOfBirth = dateOfBirth;
96 | }
97 |
98 | public Gender getGender() {
99 | return gender;
100 | }
101 |
102 | public void setGender(Gender gender) {
103 | this.gender = gender;
104 | }
105 |
106 | public Set getAddresses() {
107 | return addresses;
108 | }
109 |
110 | public void setAddresses(Set addresses) {
111 | this.addresses = addresses;
112 | }
113 |
114 | public void addAddress(Address address) {
115 |
116 | if (getAddresses() == null) {
117 | setAddresses(new HashSet<>());
118 | }
119 | getAddresses().add(address);
120 | }
121 |
122 | public static enum Gender {
123 | M, F;
124 | }
125 |
126 | }
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/endpoint/BaseEndpoint.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.endpoint;
2 |
3 | import com.droidablebee.springboot.rest.endpoint.error.Error;
4 | import jakarta.validation.ConstraintViolation;
5 | import jakarta.validation.ConstraintViolationException;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.MessageSource;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.http.ResponseEntity;
10 | import org.springframework.http.converter.HttpMessageNotReadableException;
11 | import org.springframework.security.access.AccessDeniedException;
12 | import org.springframework.validation.BindException;
13 | import org.springframework.validation.FieldError;
14 | import org.springframework.validation.ObjectError;
15 | import org.springframework.web.bind.MethodArgumentNotValidException;
16 | import org.springframework.web.bind.ServletRequestBindingException;
17 | import org.springframework.web.bind.annotation.ExceptionHandler;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | public abstract class BaseEndpoint {
23 |
24 | @Autowired
25 | protected MessageSource messageSource;
26 |
27 | @ExceptionHandler
28 | protected ResponseEntity> handleBindException(BindException exception) {
29 | return ResponseEntity.badRequest().body(convert(exception.getAllErrors()));
30 | }
31 |
32 | /**
33 | * Exception handler for validation errors caused by method parameters @RequesParam, @PathVariable, @RequestHeader annotated with jakarta.validation constraints.
34 | */
35 | @ExceptionHandler
36 | protected ResponseEntity> handleConstraintViolationException(ConstraintViolationException exception) {
37 |
38 | List errors = new ArrayList<>();
39 |
40 | for (ConstraintViolation> violation : exception.getConstraintViolations()) {
41 | String value = (violation.getInvalidValue() == null ? null : violation.getInvalidValue().toString());
42 | errors.add(new Error(violation.getPropertyPath().toString(), value, violation.getMessage()));
43 | }
44 |
45 | return ResponseEntity.badRequest().body(errors);
46 | }
47 |
48 | /**
49 | * Exception handler for @RequestBody validation errors.
50 | */
51 | @ExceptionHandler
52 | protected ResponseEntity> handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
53 |
54 | return ResponseEntity.badRequest().body(convert(exception.getBindingResult().getAllErrors()));
55 | }
56 |
57 | /**
58 | * Exception handler for missing required parameters errors.
59 | */
60 | @ExceptionHandler
61 | protected ResponseEntity> handleServletRequestBindingException(ServletRequestBindingException exception) {
62 |
63 | return ResponseEntity.badRequest().body(new Error(null, null, exception.getMessage()));
64 | }
65 |
66 | /**
67 | * Exception handler for invalid payload (e.g. json invalid format error).
68 | */
69 | @ExceptionHandler
70 | protected ResponseEntity> handleHttpMessageNotReadableException(HttpMessageNotReadableException exception) {
71 |
72 | return ResponseEntity.badRequest().body(new Error(null, null, exception.getMessage()));
73 | }
74 |
75 | @ExceptionHandler
76 | protected ResponseEntity> handleAccessDeniedException(AccessDeniedException exception) {
77 | return new ResponseEntity<>(new Error(null, null, exception.getMessage()), HttpStatus.FORBIDDEN);
78 | }
79 |
80 | @ExceptionHandler
81 | protected ResponseEntity> handleException(Exception exception) {
82 | return new ResponseEntity<>(new Error(null, null, exception.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
83 | }
84 |
85 | protected List convert(List objectErrors) {
86 |
87 | List errors = new ArrayList<>();
88 |
89 | for (ObjectError objectError : objectErrors) {
90 |
91 | String message = objectError.getDefaultMessage();
92 | if (message == null) {
93 | //when using custom spring validator org.springframework.validation.Validator need to resolve messages manually
94 | message = messageSource.getMessage(objectError, null);
95 | }
96 |
97 | Error error;
98 | if (objectError instanceof FieldError) {
99 | FieldError fieldError = (FieldError) objectError;
100 | String value = (fieldError.getRejectedValue() == null ? null : fieldError.getRejectedValue().toString());
101 | error = new Error(fieldError.getField(), value, message);
102 | } else {
103 | error = new Error(objectError.getObjectName(), objectError.getCode(), objectError.getDefaultMessage());
104 | }
105 |
106 | errors.add(error);
107 | }
108 |
109 | return errors;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/endpoint/CustomActuatorEndpoint.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.endpoint;
2 |
3 | import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
4 | import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
5 | import org.springframework.http.ResponseEntity;
6 | import org.springframework.stereotype.Component;
7 | import org.springframework.util.LinkedMultiValueMap;
8 |
9 | /**
10 | * Custom actuator endpoint.
11 | */
12 | @Component
13 | @Endpoint(id = CustomActuatorEndpoint.CUSTOM)
14 | public class CustomActuatorEndpoint {
15 |
16 | static final String CUSTOM = "custom";
17 |
18 | @ReadOperation
19 | public ResponseEntity> custom() {
20 |
21 | return ResponseEntity.ok(createCustomMap());
22 | }
23 |
24 | protected LinkedMultiValueMap createCustomMap() {
25 |
26 | return new LinkedMultiValueMap<>();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/droidablebee/springboot/rest/endpoint/InfoWebEndpointExtension.java:
--------------------------------------------------------------------------------
1 | package com.droidablebee.springboot.rest.endpoint;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
5 | import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
6 | import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
7 | import org.springframework.boot.actuate.info.InfoEndpoint;
8 | import org.springframework.stereotype.Component;
9 | import org.springframework.util.LinkedMultiValueMap;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | @Component
15 | @EndpointWebExtension(endpoint = InfoEndpoint.class)
16 | public class InfoWebEndpointExtension {
17 |
18 | @Autowired
19 | private InfoEndpoint delegate;
20 |
21 | @ReadOperation
22 | public WebEndpointResponse