19 | * Does not throw any checked {@link IOException} that occurs while trying to find a free port. If one occurs,
20 | * it will be wrapped in a {@link RuntimeException}.
21 | */
22 | public static int findFreePort() {
23 | try (ServerSocket serverSocket = new ServerSocket(0)) {
24 | serverSocket.setReuseAddress(true);
25 | return serverSocket.getLocalPort();
26 | }
27 | catch (IOException e) {
28 | throw new RuntimeException("Error while trying to find a free port.", e);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_0-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-spring6-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the [backstopper-spring-web-mvc](../../backstopper-spring-web-mvc)
10 | module's functionality works as expected in Spring 6.0.x environments, for both classpath-scanning and direct-import
11 | Backstopper configuration use cases.
12 |
13 | ## More Info
14 |
15 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
16 | source code and javadocs for all further information.
17 |
18 | ## License
19 |
20 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
21 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_1-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-spring6-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the [backstopper-spring-web-mvc](../../backstopper-spring-web-mvc)
10 | module's functionality works as expected in Spring 6.1.x environments, for both classpath-scanning and direct-import
11 | Backstopper configuration use cases.
12 |
13 | ## More Info
14 |
15 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
16 | source code and javadocs for all further information.
17 |
18 | ## License
19 |
20 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
21 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - '**'
7 | pull_request:
8 | branches:
9 | - '**'
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - name: Set up JDK 17
16 | uses: actions/setup-java@v4
17 | with:
18 | distribution: 'temurin'
19 | java-version: '17'
20 | cache: 'gradle'
21 | - name: Validate Gradle Wrapper Checksums
22 | uses: gradle/actions/wrapper-validation@v3
23 | - name: Build with Gradle
24 | run: ./gradlew clean build
25 | - name: Upload coverage report to CodeCov
26 | uses: codecov/codecov-action@v4
27 | with:
28 | files: build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml
29 | fail_ci_if_error: true
30 | verbose: true
31 | token: ${{ secrets.CODECOV_TOKEN }}
32 | - name: Upload reports and test results to GitHub
33 | uses: actions/upload-artifact@v4
34 | with:
35 | name: reports-and-test-results
36 | path: |
37 | build/reports/
38 | build/test-results/
39 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_0-webflux/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_0-webflux
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-web-flux](../../backstopper-spring-web-flux) module's functionality works as expected in
11 | Spring Boot 3.0.x WebFlux (Netty) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_1-webflux/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_1-webflux
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-web-flux](../../backstopper-spring-web-flux) module's functionality works as expected in
11 | Spring Boot 3.1.x WebFlux (Netty) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_2-webflux/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_2-webflux
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-web-flux](../../backstopper-spring-web-flux) module's functionality works as expected in
11 | Spring Boot 3.2.x WebFlux (Netty) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_3-webflux/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_3-webflux
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-web-flux](../../backstopper-spring-web-flux) module's functionality works as expected in
11 | Spring Boot 3.3.x WebFlux (Netty) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_0-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_0-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-boot3-webmvc](../../backstopper-spring-boot3-webmvc) module's functionality works as expected in
11 | Spring Boot 3.0.x Web MVC (Servlet) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_1-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_1-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-boot3-webmvc](../../backstopper-spring-boot3-webmvc) module's functionality works as expected in
11 | Spring Boot 3.1.x Web MVC (Servlet) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_2-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_2-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-boot3-webmvc](../../backstopper-spring-boot3-webmvc) module's functionality works as expected in
11 | Spring Boot 3.2.x Web MVC (Servlet) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_3-webmvc/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - testonly-springboot3_3-webmvc
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem. The Backstopper 1.x releases also contain support for Spring 4 and 5, and Springboot 1 and 2.)
8 |
9 | This submodule contains tests to verify that the
10 | [backstopper-spring-boot3-webmvc](../../backstopper-spring-boot3-webmvc) module's functionality works as expected in
11 | Spring Boot 3.3.x Web MVC (Servlet) environments, for both classpath-scanning and direct-import Backstopper configuration
12 | use cases.
13 |
14 | ## More Info
15 |
16 | See the [base project README.md](../../README.md), [User Guide](../../USER_GUIDE.md), and Backstopper repository
17 | source code and javadocs for all further information.
18 |
19 | ## License
20 |
21 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/backstopper-core/src/main/java/com/nike/backstopper/exception/network/NetworkExceptionBase.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.exception.network;
2 |
3 | /**
4 | * Base class for network exceptions that occur (e.g. during HTTP client calls to other systems).
5 | *
6 | * @author Nic Munroe
7 | */
8 | public abstract class NetworkExceptionBase extends RuntimeException {
9 |
10 | private final String connectionType;
11 |
12 | @SuppressWarnings("WeakerAccess")
13 | public NetworkExceptionBase(Throwable cause, String connectionType) {
14 | super(cause);
15 | this.connectionType = connectionType;
16 | }
17 |
18 | /**
19 | * @return The type of connection that failed. Answers the question: "what server was I trying to talk to when the
20 | * exception occurred?". Useful in case the exception handler needs to know what server was being talked
21 | * to in order to know how to process any response data contained in the exception, for example how to
22 | * parse a HTTP Status Code 400 error for useful validation data to return to the end user.
23 | */
24 | public String getConnectionType() {
25 | return connectionType;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/backstopper-core/src/test/java/com/nike/backstopper/apierror/sample/SampleProjectApiErrorsBaseTest.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.apierror.sample;
2 |
3 | import com.nike.backstopper.apierror.ApiError;
4 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrors;
5 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrorsTestBase;
6 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectSpecificErrorCodeRange;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Extension of {@link ProjectApiErrorsTestBase} that tests {@link SampleProjectApiErrorsBase}.
12 | *
13 | * @author Nic Munroe
14 | */
15 | public class SampleProjectApiErrorsBaseTest extends ProjectApiErrorsTestBase {
16 |
17 | private static final ProjectApiErrors testProjectApiErrors = new SampleProjectApiErrorsBase() {
18 | @Override
19 | protected List getProjectSpecificApiErrors() {
20 | return null;
21 | }
22 |
23 | @Override
24 | protected ProjectSpecificErrorCodeRange getProjectSpecificErrorCodeRange() {
25 | return null;
26 | }
27 | };
28 |
29 | @Override
30 | protected ProjectApiErrors getProjectApiErrors() {
31 | return testProjectApiErrors;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/samples/sample-spring-web-mvc/src/main/java/com/nike/backstopper/springsample/model/RgbColor.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.springsample.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 |
5 | /**
6 | * An enum used by {@link SampleModel} for showing how
7 | * {@link com.nike.backstopper.validation.constraints.StringConvertsToClassType} can work with enums. Note
8 | * the {@link #toRgbColor(String)} annotated with {@link JsonCreator}, which allows callers to pass in lower or
9 | * mixed case versions of the enum values and still have them automatically deserialized to the correct enum.
10 | * This special {@link JsonCreator} method is only necessary if you want to support case-insensitive enum validation
11 | * when deserializing.
12 | */
13 | public enum RgbColor {
14 | RED, GREEN, BLUE;
15 |
16 | @JsonCreator
17 | @SuppressWarnings("unused")
18 | public static RgbColor toRgbColor(String colorString) {
19 | for (RgbColor color : values()) {
20 | if (color.name().equalsIgnoreCase(colorString))
21 | return color;
22 | }
23 | throw new IllegalArgumentException(
24 | "Cannot convert the string: \"" + colorString + "\" to a valid RgbColor enum value."
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/backstopper-core/src/test/java/com/nike/backstopper/exception/ServersideValidationErrorTest.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.exception;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.HashSet;
6 | import java.util.Set;
7 |
8 | import jakarta.validation.ConstraintViolation;
9 |
10 | import static org.hamcrest.CoreMatchers.is;
11 | import static org.hamcrest.MatcherAssert.assertThat;
12 |
13 | /**
14 | * Tests the functionality of {@link ServersideValidationError}. Since there isn't really much functionality,
15 | * this just verifies that the constructors/etc work without blowing up.
16 | *
17 | * @author Nic Munroe
18 | */
19 | public class ServersideValidationErrorTest {
20 |
21 | @Test
22 | public void verifyObjectThatFailedValidationIsSet() {
23 | Object someObj = new Object();
24 | ServersideValidationError ex = new ServersideValidationError(someObj, null);
25 | assertThat(ex.getObjectThatFailedValidation(), is(someObj));
26 | }
27 |
28 | @Test
29 | public void verifyViolationsIsSet() {
30 | Set> violations = new HashSet<>();
31 | ServersideValidationError ex = new ServersideValidationError(null, violations);
32 | assertThat(ex.getViolations(), is(violations));
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/samples/sample-spring-boot3-webmvc/src/main/java/com/nike/backstopper/springboot3webmvcsample/model/RgbColor.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.springboot3webmvcsample.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 |
5 | /**
6 | * An enum used by {@link SampleModel} for showing how
7 | * {@link com.nike.backstopper.validation.constraints.StringConvertsToClassType} can work with enums. Note
8 | * the {@link #toRgbColor(String)} annotated with {@link JsonCreator}, which allows callers to pass in lower or
9 | * mixed case versions of the enum values and still have them automatically deserialized to the correct enum.
10 | * This special {@link JsonCreator} method is only necessary if you want to support case-insensitive enum validation
11 | * when deserializing.
12 | */
13 | public enum RgbColor {
14 | RED, GREEN, BLUE;
15 |
16 | @JsonCreator
17 | @SuppressWarnings("unused")
18 | public static RgbColor toRgbColor(String colorString) {
19 | for (RgbColor color : values()) {
20 | if (color.name().equalsIgnoreCase(colorString))
21 | return color;
22 | }
23 | throw new IllegalArgumentException(
24 | "Cannot convert the string: \"" + colorString + "\" to a valid RgbColor enum value."
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/sample-spring-boot3-webflux/src/main/java/com/nike/backstopper/springboot3webfluxsample/model/RgbColor.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.springboot3webfluxsample.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 |
5 | /**
6 | * An enum used by {@link SampleModel} for showing how
7 | * {@link com.nike.backstopper.validation.constraints.StringConvertsToClassType} can work with enums. Note
8 | * the {@link #toRgbColor(String)} annotated with {@link JsonCreator}, which allows callers to pass in lower or
9 | * mixed case versions of the enum values and still have them automatically deserialized to the correct enum.
10 | * This special {@link JsonCreator} method is only necessary if you want to support case-insensitive enum validation
11 | * when deserializing.
12 | */
13 | public enum RgbColor {
14 | RED, GREEN, BLUE;
15 |
16 | @JsonCreator
17 | @SuppressWarnings("unused")
18 | public static RgbColor toRgbColor(String colorString) {
19 | for (RgbColor color : values()) {
20 | if (color.name().equalsIgnoreCase(colorString))
21 | return color;
22 | }
23 | throw new IllegalArgumentException(
24 | "Cannot convert the string: \"" + colorString + "\" to a valid RgbColor enum value."
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webflux-reusable-test-support/src/main/java/testonly/componenttest/spring/reusable/model/RgbColor.java:
--------------------------------------------------------------------------------
1 | package testonly.componenttest.spring.reusable.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 |
5 | /**
6 | * An enum used by {@link SampleModel} for showing how
7 | * {@link com.nike.backstopper.validation.constraints.StringConvertsToClassType} can work with enums. Note
8 | * the {@link #toRgbColor(String)} annotated with {@link JsonCreator}, which allows callers to pass in lower or
9 | * mixed case versions of the enum values and still have them automatically deserialized to the correct enum.
10 | * This special {@link JsonCreator} method is only necessary if you want to support case-insensitive enum validation
11 | * when deserializing.
12 | */
13 | public enum RgbColor {
14 | RED, GREEN, BLUE;
15 |
16 | @JsonCreator
17 | @SuppressWarnings("unused")
18 | public static RgbColor toRgbColor(String colorString) {
19 | for (RgbColor color : values()) {
20 | if (color.name().equalsIgnoreCase(colorString))
21 | return color;
22 | }
23 | throw new IllegalArgumentException(
24 | "Cannot convert the string: \"" + colorString + "\" to a valid RgbColor enum value."
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webmvc-reusable-test-support/src/main/java/testonly/componenttest/spring/reusable/model/RgbColor.java:
--------------------------------------------------------------------------------
1 | package testonly.componenttest.spring.reusable.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 |
5 | /**
6 | * An enum used by {@link SampleModel} for showing how
7 | * {@link com.nike.backstopper.validation.constraints.StringConvertsToClassType} can work with enums. Note
8 | * the {@link #toRgbColor(String)} annotated with {@link JsonCreator}, which allows callers to pass in lower or
9 | * mixed case versions of the enum values and still have them automatically deserialized to the correct enum.
10 | * This special {@link JsonCreator} method is only necessary if you want to support case-insensitive enum validation
11 | * when deserializing.
12 | */
13 | public enum RgbColor {
14 | RED, GREEN, BLUE;
15 |
16 | @JsonCreator
17 | @SuppressWarnings("unused")
18 | public static RgbColor toRgbColor(String colorString) {
19 | for (RgbColor color : values()) {
20 | if (color.name().equalsIgnoreCase(colorString))
21 | return color;
22 | }
23 | throw new IllegalArgumentException(
24 | "Cannot convert the string: \"" + colorString + "\" to a valid RgbColor enum value."
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/backstopper-core/src/main/java/com/nike/backstopper/exception/StackTraceLoggingBehavior.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.exception;
2 |
3 | /**
4 | * An enum representing the options available for whether the stack trace is logged for a given exception caught and
5 | * handled by Backstopper. {@link ApiException} includes this as an optional field you can set which Backstopper will
6 | * honor when handling the {@link ApiException}.
7 | */
8 | public enum StackTraceLoggingBehavior {
9 | /**
10 | * This option forces Backstopper to log the stack trace of the exception, even if it would normally not log the
11 | * stack trace (e.g. if the exception represents a 4xx error).
12 | */
13 | FORCE_STACK_TRACE,
14 | /**
15 | * This option forces Backstopper to *not* log the stack trace of the exception, even if it would normally log the
16 | * stack trace (e.g. if the exception represents a 5xx error).
17 | */
18 | FORCE_NO_STACK_TRACE,
19 | /**
20 | * This option lets Backstopper decide whether or not the stack trace of the exception should be logged. This
21 | * usually means the stack trace will be logged for an exception representing a 5xx error, and no stack trace for
22 | * exceptions representing a 4xx error.
23 | */
24 | DEFER_TO_DEFAULT_BEHAVIOR
25 | }
26 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webmvc-reusable-test-support/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | test {
4 | useJUnitPlatform()
5 | }
6 |
7 | dependencies {
8 | compileOnly(
9 | project(":backstopper-spring-web-mvc"),
10 | project(":backstopper-custom-validators"),
11 | "org.springframework:spring-webmvc:$spring6_0Version",
12 | "org.eclipse.jetty:jetty-webapp:$jettyVersion",
13 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
14 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
15 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
16 | "com.fasterxml.jackson.core:jackson-core:$jacksonVersion",
17 | "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
18 | "io.rest-assured:rest-assured:$restAssuredVersion",
19 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
20 | "commons-codec:commons-codec:$commonsCodecVersion",
21 | "org.assertj:assertj-core:$assertJVersion",
22 | )
23 | testImplementation(
24 | project(":backstopper-reusable-tests-junit5"),
25 | "org.springframework:spring-webmvc:$spring6_0Version",
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webflux-reusable-test-support/src/test/java/jsr303convention/VerifyJsr303ContractTest.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.backstopper.apierror.contract.jsr303convention.VerifyJsr303ValidationMessagesPointToApiErrorsTest;
5 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrors;
6 |
7 | import testonly.componenttest.spring.reusable.error.SampleProjectApiErrorsImpl;
8 |
9 | /**
10 | * Verifies that *ALL* non-excluded JSR 303 validation annotations in this project have a message defined that maps to a
11 | * {@link com.nike.backstopper.apierror.ApiError} enum name from this project's {@link SampleProjectApiErrorsImpl}.
12 | */
13 | public class VerifyJsr303ContractTest extends VerifyJsr303ValidationMessagesPointToApiErrorsTest {
14 |
15 | private static final ProjectApiErrors PROJECT_API_ERRORS = new SampleProjectApiErrorsImpl();
16 |
17 | @Override
18 | protected ReflectionBasedJsr303AnnotationTrollerBase getAnnotationTroller() {
19 | return ApplicationJsr303AnnotationTroller.getInstance();
20 | }
21 |
22 | @Override
23 | protected ProjectApiErrors getProjectApiErrors() {
24 | return PROJECT_API_ERRORS;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webmvc-reusable-test-support/src/test/java/jsr303convention/VerifyJsr303ContractTest.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.backstopper.apierror.contract.jsr303convention.VerifyJsr303ValidationMessagesPointToApiErrorsTest;
5 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrors;
6 |
7 | import testonly.componenttest.spring.reusable.error.SampleProjectApiErrorsImpl;
8 |
9 | /**
10 | * Verifies that *ALL* non-excluded JSR 303 validation annotations in this project have a message defined that maps to a
11 | * {@link com.nike.backstopper.apierror.ApiError} enum name from this project's {@link SampleProjectApiErrorsImpl}.
12 | */
13 | public class VerifyJsr303ContractTest extends VerifyJsr303ValidationMessagesPointToApiErrorsTest {
14 |
15 | private static final ProjectApiErrors PROJECT_API_ERRORS = new SampleProjectApiErrorsImpl();
16 |
17 | @Override
18 | protected ReflectionBasedJsr303AnnotationTrollerBase getAnnotationTroller() {
19 | return ApplicationJsr303AnnotationTroller.getInstance();
20 | }
21 |
22 | @Override
23 | protected ProjectApiErrors getProjectApiErrors() {
24 | return PROJECT_API_ERRORS;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'backstopper'
2 |
3 | // Published-artifact modules
4 | include "nike-internal-util",
5 | "backstopper-core",
6 | "backstopper-custom-validators",
7 | "backstopper-reusable-tests-junit5",
8 | "backstopper-jackson",
9 | "backstopper-servlet-api",
10 | "backstopper-spring-web",
11 | "backstopper-spring-web-mvc",
12 | "backstopper-spring-web-flux",
13 | "backstopper-spring-boot3-webmvc",
14 | // Test-only modules (not published)
15 | "testonly:testonly-spring-webmvc-reusable-test-support",
16 | "testonly:testonly-spring-webflux-reusable-test-support",
17 | "testonly:testonly-spring-6_0-webmvc",
18 | "testonly:testonly-spring-6_1-webmvc",
19 | "testonly:testonly-springboot3_0-webmvc",
20 | "testonly:testonly-springboot3_0-webflux",
21 | "testonly:testonly-springboot3_1-webmvc",
22 | "testonly:testonly-springboot3_1-webflux",
23 | "testonly:testonly-springboot3_2-webmvc",
24 | "testonly:testonly-springboot3_2-webflux",
25 | "testonly:testonly-springboot3_3-webmvc",
26 | "testonly:testonly-springboot3_3-webflux",
27 | // Sample modules (not published)
28 | "samples:sample-spring-web-mvc",
29 | "samples:sample-spring-boot3-webmvc",
30 | "samples:sample-spring-boot3-webflux"
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_0-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | test {
4 | useJUnitPlatform()
5 | }
6 |
7 | dependencies {
8 | implementation(
9 | project(":backstopper-spring-web-mvc"),
10 | project(":backstopper-custom-validators"),
11 | "org.springframework:spring-webmvc:$spring6_0Version",
12 | "ch.qos.logback:logback-classic:$logbackVersion",
13 | "com.fasterxml.jackson.core:jackson-core:$jacksonVersion",
14 | "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
15 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
16 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
17 | "org.eclipse.jetty:jetty-webapp:$jettyVersion",
18 | )
19 | testImplementation(
20 | project(":backstopper-reusable-tests-junit5"),
21 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
22 | "org.junit.jupiter:junit-jupiter:$junit5Version",
23 | "org.mockito:mockito-core:$mockitoVersion",
24 | "org.assertj:assertj-core:$assertJVersion",
25 | "io.rest-assured:rest-assured:$restAssuredVersion",
26 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
27 | "commons-codec:commons-codec:$commonsCodecVersion",
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_1-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | test {
4 | useJUnitPlatform()
5 | }
6 |
7 | dependencies {
8 | implementation(
9 | project(":backstopper-spring-web-mvc"),
10 | project(":backstopper-custom-validators"),
11 | "org.springframework:spring-webmvc:$spring6_1Version",
12 | "ch.qos.logback:logback-classic:$logbackVersion",
13 | "com.fasterxml.jackson.core:jackson-core:$jacksonVersion",
14 | "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
15 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
16 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
17 | "org.eclipse.jetty:jetty-webapp:$jettyVersion",
18 | )
19 | testImplementation(
20 | project(":backstopper-reusable-tests-junit5"),
21 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
22 | "org.junit.jupiter:junit-jupiter:$junit5Version",
23 | "org.mockito:mockito-core:$mockitoVersion",
24 | "org.assertj:assertj-core:$assertJVersion",
25 | "io.rest-assured:rest-assured:$restAssuredVersion",
26 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
27 | "commons-codec:commons-codec:$commonsCodecVersion",
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/samples/sample-spring-web-mvc/src/test/java/com/nike/backstopper/apierror/contract/jsr303convention/VerifyStringConvertsToClassTypeAnnotationsAreValidTest.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.apierror.contract.jsr303convention;
2 |
3 | import com.nike.backstopper.validation.constraints.StringConvertsToClassType;
4 |
5 | /**
6 | * Makes sure that any Enums referenced by {@link StringConvertsToClassType} JSR 303 annotations are case insensitive if
7 | * they are marked with {@link StringConvertsToClassType#allowCaseInsensitiveEnumMatch()} set to true.
8 | *
9 | *
You can exclude annotation declarations (e.g. for unit test classes that are intended to violate the naming
10 | * convention) by making sure that the {@link ApplicationJsr303AnnotationTroller#ignoreAllAnnotationsAssociatedWithTheseProjectClasses()}
11 | * and {@link ApplicationJsr303AnnotationTroller#specificAnnotationDeclarationExclusionsForProject()} methods return
12 | * what you need, but you should not exclude any annotations in production code under normal circumstances.
13 | *
14 | * @author Nic Munroe
15 | */
16 | public class VerifyStringConvertsToClassTypeAnnotationsAreValidTest
17 | extends VerifyEnumsReferencedByStringConvertsToClassTypeJsr303AnnotationsAreJacksonCaseInsensitiveTest {
18 |
19 | @Override
20 | protected ReflectionBasedJsr303AnnotationTrollerBase getAnnotationTroller() {
21 | return ApplicationJsr303AnnotationTroller.getInstance();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/backstopper-spring-web-flux/src/test/java/com/nike/backstopper/handler/spring/webflux/componenttest/model/SampleModel.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.handler.spring.webflux.componenttest.model;
2 |
3 | import com.nike.backstopper.validation.constraints.StringConvertsToClassType;
4 |
5 | import org.hibernate.validator.constraints.Range;
6 |
7 | import jakarta.validation.constraints.NotBlank;
8 | import jakarta.validation.constraints.NotNull;
9 |
10 | public class SampleModel {
11 | @NotBlank(message = "FOO_STRING_CANNOT_BE_BLANK")
12 | public final String foo;
13 |
14 | @Range(message = "INVALID_RANGE_VALUE", min = 0, max = 42)
15 | public final String range_0_to_42;
16 |
17 | @NotNull(message = "RGB_COLOR_CANNOT_BE_NULL")
18 | @StringConvertsToClassType(
19 | message = "NOT_RGB_COLOR_ENUM", classType = RgbColor.class, allowCaseInsensitiveEnumMatch = true
20 | )
21 | public final String rgb_color;
22 |
23 | public final Boolean throw_manual_error;
24 |
25 | @SuppressWarnings("unused")
26 | // Intentionally protected - here for deserialization support.
27 | protected SampleModel() {
28 | this(null, null, null, null);
29 | }
30 |
31 | public SampleModel(String foo, String range_0_to_42, String rgb_color, Boolean throw_manual_error) {
32 | this.foo = foo;
33 | this.range_0_to_42 = range_0_to_42;
34 | this.rgb_color = rgb_color;
35 | this.throw_manual_error = throw_manual_error;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/backstopper-reusable-tests-junit5/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | ext {
4 | mockito3Version = '3.12.4'
5 | javassistJava8Version = '3.29.0-GA'
6 | orgReflectionsUpdatedVersion = '0.9.12'
7 | }
8 |
9 | test {
10 | useJUnitPlatform()
11 | }
12 |
13 | dependencies {
14 | api(
15 | project(":backstopper-core"),
16 | project(":backstopper-custom-validators"),
17 | "com.fasterxml.jackson.core:jackson-core:$jacksonVersion",
18 | "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
19 | "org.junit.jupiter:junit-jupiter:$junit5Version",
20 | "org.mockito:mockito-core:$mockito3Version",
21 | "org.assertj:assertj-core:$assertJVersion",
22 | "org.reflections:reflections:$orgReflectionsUpdatedVersion",
23 | "org.javassist:javassist:$javassistJava8Version"
24 | )
25 | compileOnly(
26 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
27 | )
28 | testImplementation(
29 | "org.junit.jupiter:junit-jupiter:$junit5Version",
30 | "org.slf4j:slf4j-api:$slf4jVersion",
31 | "ch.qos.logback:logback-classic:$logbackVersion",
32 | )
33 | // Make gradle happy for gradle 9.
34 | // See: https://docs.gradle.org/8.10/userguide/upgrading_version_8.html#test_framework_implementation_dependencies
35 | testRuntimeOnly(
36 | "org.junit.platform:junit-platform-launcher"
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/samples/sample-spring-web-mvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | test {
4 | useJUnitPlatform()
5 | }
6 |
7 | dependencies {
8 | implementation(
9 | project(":backstopper-spring-web-mvc"),
10 | project(":backstopper-custom-validators"),
11 | "org.springframework:spring-webmvc:$spring6_0Version",
12 | "ch.qos.logback:logback-classic:$logbackVersion",
13 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
14 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
15 | "org.eclipse.jetty:jetty-webapp:$jettyVersion"
16 | )
17 | compileOnly(
18 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
19 | )
20 | testImplementation(
21 | project(":backstopper-reusable-tests-junit5"),
22 | "org.junit.jupiter:junit-jupiter:$junit5Version",
23 | "org.mockito:mockito-core:$mockitoVersion",
24 | "org.assertj:assertj-core:$assertJVersion",
25 | "io.rest-assured:rest-assured:$restAssuredVersion",
26 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
27 | "commons-codec:commons-codec:$commonsCodecVersion",
28 | )
29 | }
30 |
31 | apply plugin: "application"
32 | application {
33 | setMainClass("com.nike.backstopper.springsample.Main")
34 | }
35 |
36 | run {
37 | systemProperties(System.getProperties())
38 | }
39 |
--------------------------------------------------------------------------------
/backstopper-reusable-tests-junit5/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - reusable-tests
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem.)
8 |
9 | This library contains some reusable unit test classes that should be integrated into every Backstopper-enabled
10 | project to guarantee that the conventions and rules that Backstopper requires are followed. This is a fairly easy
11 | process and is described in detail in the Backstopper User Guide in the [Reusable Unit Tests for Enforcing
12 | Backstopper Rules and Conventions](../USER_GUIDE.md#reusable_tests) section.
13 |
14 | Beyond that, the classes in this reusable-tests library are heavily documented with extensive javadocs, and the
15 | [sample applications](../README.md#samples) show concrete usage of these tests to enforce the rules and conventions.
16 | Please explore the source code and samples to learn more.
17 |
18 | ## More Info
19 |
20 | See the [base project README.md](../README.md), [User Guide](../USER_GUIDE.md), and Backstopper repository source
21 | code and javadocs for all further information.
22 |
23 | ## License
24 |
25 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/backstopper-core/src/main/java/com/nike/backstopper/exception/WrapperException.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.exception;
2 |
3 | /**
4 | * Simple wrapper exception that you can use when you want the error handling system to handle the
5 | * {@link WrapperException#getCause()} of this instance rather than this instance itself, but still log the entire
6 | * stack trace (including this instance). This is often necessary in asynchronous scenarios where you want to add
7 | * stack trace info for the logs but don't want to obscure the true cause of the error.
8 | *
9 | * @author Nic Munroe
10 | */
11 | @SuppressWarnings("WeakerAccess")
12 | public class WrapperException extends RuntimeException {
13 |
14 | protected String toStringCache;
15 |
16 | public WrapperException(String message, Throwable cause) {
17 | super(message, cause);
18 | }
19 |
20 | public WrapperException(Throwable cause) {
21 | super(cause);
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | if (toStringCache == null) {
27 | String cacheVal = super.toString();
28 | if (getCause() != null) {
29 | String causeToString = getCause().toString();
30 | if (!cacheVal.endsWith(causeToString)) {
31 | cacheVal += " -- Wrapped toString(): " + getCause().toString();
32 | }
33 | }
34 |
35 | toStringCache = cacheVal;
36 | }
37 |
38 | return toStringCache;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webmvc-reusable-test-support/src/main/java/testonly/componenttest/spring/reusable/error/SampleProjectApiErrorsImpl.java:
--------------------------------------------------------------------------------
1 | package testonly.componenttest.spring.reusable.error;
2 |
3 | import com.nike.backstopper.apierror.ApiError;
4 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectSpecificErrorCodeRange;
5 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectSpecificErrorCodeRangeIntegerImpl;
6 | import com.nike.backstopper.apierror.sample.SampleProjectApiErrorsBase;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.List;
11 |
12 | import jakarta.inject.Singleton;
13 |
14 | /**
15 | * Returns the project specific errors for the {@code testonly-spring*} component tests.
16 | */
17 | @Singleton
18 | public class SampleProjectApiErrorsImpl extends SampleProjectApiErrorsBase {
19 |
20 | private static final List projectSpecificApiErrors =
21 | new ArrayList<>(Arrays.asList(SampleProjectApiError.values()));
22 |
23 | private static final ProjectSpecificErrorCodeRange errorCodeRange = new ProjectSpecificErrorCodeRangeIntegerImpl(
24 | 99100, 99200, "SAMPLE_PROJECT_API_ERRORS"
25 | );
26 |
27 | @Override
28 | protected List getProjectSpecificApiErrors() {
29 | return projectSpecificApiErrors;
30 | }
31 |
32 | @Override
33 | protected ProjectSpecificErrorCodeRange getProjectSpecificErrorCodeRange() {
34 | return errorCodeRange;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webflux-reusable-test-support/src/main/java/testonly/componenttest/spring/reusable/error/SampleProjectApiErrorsImpl.java:
--------------------------------------------------------------------------------
1 | package testonly.componenttest.spring.reusable.error;
2 |
3 | import com.nike.backstopper.apierror.ApiError;
4 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectSpecificErrorCodeRange;
5 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectSpecificErrorCodeRangeIntegerImpl;
6 | import com.nike.backstopper.apierror.sample.SampleProjectApiErrorsBase;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.List;
11 |
12 | import jakarta.inject.Singleton;
13 |
14 | /**
15 | * Returns the project specific errors for the {@code testonly-spring*} component tests.
16 | */
17 | @Singleton
18 | public class SampleProjectApiErrorsImpl extends SampleProjectApiErrorsBase {
19 |
20 | private static final List projectSpecificApiErrors =
21 | new ArrayList<>(Arrays.asList(SampleProjectApiError.values()));
22 |
23 | private static final ProjectSpecificErrorCodeRange errorCodeRange = new ProjectSpecificErrorCodeRangeIntegerImpl(
24 | 99100, 99200, "SAMPLE_PROJECT_API_ERRORS"
25 | );
26 |
27 | @Override
28 | protected List getProjectSpecificApiErrors() {
29 | return projectSpecificApiErrors;
30 | }
31 |
32 | @Override
33 | protected ProjectSpecificErrorCodeRange getProjectSpecificErrorCodeRange() {
34 | return errorCodeRange;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/nike-internal-util/src/main/java/com/nike/internal/util/MapBuilder.java:
--------------------------------------------------------------------------------
1 | package com.nike.internal.util;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * Simple fluent map builder that allows you to easily initialize static map fields with hardcoded data. We could use
8 | * the Guava library's ImmutableMap, but there's no reason to require pulling in all of Guava just for this one simple
9 | * thing.
10 | *
11 | * @author Nic Munroe
12 | */
13 | @SuppressWarnings("WeakerAccess")
14 | public class MapBuilder {
15 |
16 | private final Map map = new HashMap<>();
17 |
18 | private MapBuilder() { /* private to enforce builder pattern */ }
19 |
20 | public static MapBuilder builder() {
21 | return new MapBuilder<>();
22 | }
23 |
24 | public static MapBuilder builder(K firstKey, V firstVal) {
25 | MapBuilder builder = new MapBuilder<>();
26 | builder.put(firstKey, firstVal);
27 | return builder;
28 | }
29 |
30 | public MapBuilder put(K key, V value) {
31 | map.put(key, value);
32 | return this;
33 | }
34 |
35 | @SuppressWarnings("UnusedReturnValue")
36 | public MapBuilder putAll(Map otherMap) {
37 | for (Map.Entry entry : otherMap.entrySet()) {
38 | put(entry.getKey(), entry.getValue());
39 | }
40 | return this;
41 | }
42 |
43 | public Map build() {
44 | return new HashMap<>(map);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/backstopper-spring-web-mvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | dependencies {
4 | api(
5 | project(":backstopper-servlet-api"),
6 | project(":backstopper-jackson"),
7 | project(":backstopper-spring-web"),
8 | )
9 | compileOnly(
10 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
11 | "org.springframework:spring-webmvc:$spring6_0Version",
12 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
13 | )
14 | testImplementation(
15 | project(":backstopper-core").sourceSets.test.output,
16 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
17 | "junit:junit:$junitVersion",
18 | "org.mockito:mockito-core:$mockitoVersion",
19 | "ch.qos.logback:logback-classic:$logbackVersion",
20 | "org.assertj:assertj-core:$assertJVersion",
21 | "com.tngtech.java:junit-dataprovider:$junitDataproviderVersion",
22 | "org.hamcrest:hamcrest-all:$hamcrestVersion",
23 | "org.springframework:spring-test:$spring6_0Version",
24 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
25 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
26 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
27 | "org.springframework:spring-webmvc:$spring6_0Version",
28 | "org.springframework.security:spring-security-core:$springSecurityVersion",
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/backstopper-jackson/README.md:
--------------------------------------------------------------------------------
1 | # Backstopper - jackson
2 |
3 | Backstopper is a framework-agnostic API error handling and (optional) model validation solution for Java 17 and greater.
4 |
5 | (NOTE: The [Backstopper 1.x branch](https://github.com/Nike-Inc/backstopper/tree/v1.x) contains a version of
6 | Backstopper for Java 7+, and for the `javax` ecosystem. The current Backstopper supports Java 17+ and the `jakarta`
7 | ecosystem.)
8 |
9 | This library contains some helper classes for working in an environment that uses Jackson with Backstopper.
10 |
11 | ## Helper classes
12 |
13 | * **`JsonUtilWithDefaultErrorContractDTOSupport`** - A general-purpose JSON serializer that has built-in support for the
14 | default Backstopper error contract DTO. In particular:
15 | * If an error code is parseable to an integer then the JSON field for that error code will be serialized as a number
16 | rather than a string.
17 | * If an error has an empty metadata section then it will be omitted from the serialized JSON.
18 | * You can create a Jackson `ObjectMapper` with any combination of the above rules turned on or off by using the
19 | `generateErrorContractObjectMapper(...)` static factory method.
20 |
21 | ## More Info
22 |
23 | See the [base project README.md](../README.md), [User Guide](../USER_GUIDE.md), and Backstopper repository source code
24 | and javadocs for all further information.
25 |
26 | ## License
27 |
28 | Backstopper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/backstopper-spring-web/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | dependencies {
4 | api(
5 | project(":backstopper-core"),
6 | )
7 | compileOnly(
8 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
9 | "org.springframework:spring-web:$spring6_0Version",
10 | "org.springframework:spring-context:$spring6_0Version",
11 | )
12 | testImplementation(
13 | project(":backstopper-core").sourceSets.test.output,
14 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
15 | "junit:junit:$junitVersion",
16 | "org.hamcrest:hamcrest-all:$hamcrestVersion",
17 | "org.mockito:mockito-core:$mockitoVersion",
18 | "ch.qos.logback:logback-classic:$logbackVersion",
19 | "org.assertj:assertj-core:$assertJVersion",
20 | "com.tngtech.java:junit-dataprovider:$junitDataproviderVersion",
21 | "com.fasterxml.jackson.core:jackson-core:$jacksonVersion",
22 | "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
23 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
24 | "org.springframework:spring-web:$spring6_0Version",
25 | "org.springframework:spring-context:$spring6_0Version",
26 | "org.springframework.security:spring-security-core:$springSecurityVersion",
27 | "org.springframework:spring-webmvc:$spring6_0Version",
28 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_0-webmvc/src/test/java/serverconfig/classpathscan/Spring_6_0_WebMvcClasspathScanConfig.java:
--------------------------------------------------------------------------------
1 | package serverconfig.classpathscan;
2 |
3 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrors;
4 |
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.ComponentScan;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
9 |
10 | import jakarta.validation.Validation;
11 | import jakarta.validation.Validator;
12 | import testonly.componenttest.spring.reusable.error.SampleProjectApiErrorsImpl;
13 |
14 | /**
15 | * Spring config that uses {@link ComponentScan} to integrate Backstopper via classpath scanning of the
16 | * {@code com.nike.backstopper} package.
17 | *
18 | * @author Nic Munroe
19 | */
20 | @Configuration
21 | @ComponentScan(basePackages = {
22 | // Component scan the core Backstopper+Spring support.
23 | "com.nike.backstopper",
24 | // Component scan the controller.
25 | "testonly.componenttest.spring.reusable.controller"
26 | })
27 | @EnableWebMvc
28 | @SuppressWarnings("unused")
29 | public class Spring_6_0_WebMvcClasspathScanConfig {
30 |
31 | @Bean
32 | public ProjectApiErrors getProjectApiErrors() {
33 | return new SampleProjectApiErrorsImpl();
34 | }
35 |
36 | @Bean
37 | public Validator getJsr303Validator() {
38 | //noinspection resource
39 | return Validation.buildDefaultValidatorFactory().getValidator();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-6_1-webmvc/src/test/java/serverconfig/classpathscan/Spring_6_1_WebMvcClasspathScanConfig.java:
--------------------------------------------------------------------------------
1 | package serverconfig.classpathscan;
2 |
3 | import com.nike.backstopper.apierror.projectspecificinfo.ProjectApiErrors;
4 |
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.ComponentScan;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
9 |
10 | import jakarta.validation.Validation;
11 | import jakarta.validation.Validator;
12 | import testonly.componenttest.spring.reusable.error.SampleProjectApiErrorsImpl;
13 |
14 | /**
15 | * Spring config that uses {@link ComponentScan} to integrate Backstopper via classpath scanning of the
16 | * {@code com.nike.backstopper} package.
17 | *
18 | * @author Nic Munroe
19 | */
20 | @Configuration
21 | @ComponentScan(basePackages = {
22 | // Component scan the core Backstopper+Spring support.
23 | "com.nike.backstopper",
24 | // Component scan the controller.
25 | "testonly.componenttest.spring.reusable.controller"
26 | })
27 | @EnableWebMvc
28 | @SuppressWarnings("unused")
29 | public class Spring_6_1_WebMvcClasspathScanConfig {
30 |
31 | @Bean
32 | public ProjectApiErrors getProjectApiErrors() {
33 | return new SampleProjectApiErrorsImpl();
34 | }
35 |
36 | @Bean
37 | public Validator getJsr303Validator() {
38 | //noinspection resource
39 | return Validation.buildDefaultValidatorFactory().getValidator();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/backstopper-spring-boot3-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | dependencies {
4 | api(
5 | project(":backstopper-spring-web-mvc"),
6 | )
7 | compileOnly(
8 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
9 | "org.springframework.boot:spring-boot-autoconfigure:$springboot3_3Version",
10 | "org.springframework:spring-webmvc:$spring6_0Version",
11 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
12 | )
13 | testImplementation(
14 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
15 | "junit:junit:$junitVersion",
16 | "org.mockito:mockito-core:$mockitoVersion",
17 | "ch.qos.logback:logback-classic:$logbackVersion",
18 | "org.assertj:assertj-core:$assertJVersion",
19 | "com.tngtech.java:junit-dataprovider:$junitDataproviderVersion",
20 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
21 | "io.rest-assured:rest-assured:$restAssuredVersion",
22 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
23 | "commons-codec:commons-codec:$commonsCodecVersion",
24 | "jakarta.servlet:jakarta.servlet-api:$servletApiVersion",
25 | "org.springframework.boot:spring-boot-starter-web:$springboot3_3Version",
26 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_0-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot3_0Version}")
9 | }
10 | }
11 |
12 | apply plugin: 'org.springframework.boot'
13 | apply plugin: "io.spring.dependency-management"
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | dependencies {
20 | implementation(
21 | project(":backstopper-spring-boot3-webmvc"),
22 | project(":backstopper-custom-validators"),
23 | "ch.qos.logback:logback-classic",
24 | "org.springframework.boot:spring-boot-dependencies:$springboot3_0Version",
25 | "org.springframework.boot:spring-boot-starter-web",
26 | "org.hibernate.validator:hibernate-validator",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | testImplementation(
30 | project(":backstopper-reusable-tests-junit5"),
31 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
32 | "org.junit.jupiter:junit-jupiter:$junit5Version",
33 | "org.mockito:mockito-core:$mockitoVersion",
34 | "org.assertj:assertj-core:$assertJVersion",
35 | "io.rest-assured:rest-assured",
36 | )
37 | }
38 |
39 | // We're just running tests, not trying to stand up a real Springboot 3 server from gradle.
40 | // Disable the bootJar task so gradle doesn't fall over.
41 | bootJar.enabled = false
42 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_1-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot3_1Version}")
9 | }
10 | }
11 |
12 | apply plugin: 'org.springframework.boot'
13 | apply plugin: "io.spring.dependency-management"
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | dependencies {
20 | implementation(
21 | project(":backstopper-spring-boot3-webmvc"),
22 | project(":backstopper-custom-validators"),
23 | "ch.qos.logback:logback-classic",
24 | "org.springframework.boot:spring-boot-dependencies:$springboot3_1Version",
25 | "org.springframework.boot:spring-boot-starter-web",
26 | "org.hibernate.validator:hibernate-validator",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | testImplementation(
30 | project(":backstopper-reusable-tests-junit5"),
31 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
32 | "org.junit.jupiter:junit-jupiter:$junit5Version",
33 | "org.mockito:mockito-core:$mockitoVersion",
34 | "org.assertj:assertj-core:$assertJVersion",
35 | "io.rest-assured:rest-assured",
36 | )
37 | }
38 |
39 | // We're just running tests, not trying to stand up a real Springboot 3 server from gradle.
40 | // Disable the bootJar task so gradle doesn't fall over.
41 | bootJar.enabled = false
42 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_2-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot3_2Version}")
9 | }
10 | }
11 |
12 | apply plugin: 'org.springframework.boot'
13 | apply plugin: "io.spring.dependency-management"
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | dependencies {
20 | implementation(
21 | project(":backstopper-spring-boot3-webmvc"),
22 | project(":backstopper-custom-validators"),
23 | "ch.qos.logback:logback-classic",
24 | "org.springframework.boot:spring-boot-dependencies:$springboot3_2Version",
25 | "org.springframework.boot:spring-boot-starter-web",
26 | "org.hibernate.validator:hibernate-validator",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | testImplementation(
30 | project(":backstopper-reusable-tests-junit5"),
31 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
32 | "org.junit.jupiter:junit-jupiter:$junit5Version",
33 | "org.mockito:mockito-core:$mockitoVersion",
34 | "org.assertj:assertj-core:$assertJVersion",
35 | "io.rest-assured:rest-assured",
36 | )
37 | }
38 |
39 | // We're just running tests, not trying to stand up a real Springboot 3 server from gradle.
40 | // Disable the bootJar task so gradle doesn't fall over.
41 | bootJar.enabled = false
42 |
--------------------------------------------------------------------------------
/testonly/testonly-springboot3_3-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot3_3Version}")
9 | }
10 | }
11 |
12 | apply plugin: 'org.springframework.boot'
13 | apply plugin: "io.spring.dependency-management"
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | dependencies {
20 | implementation(
21 | project(":backstopper-spring-boot3-webmvc"),
22 | project(":backstopper-custom-validators"),
23 | "ch.qos.logback:logback-classic",
24 | "org.springframework.boot:spring-boot-dependencies:$springboot3_3Version",
25 | "org.springframework.boot:spring-boot-starter-web",
26 | "org.hibernate.validator:hibernate-validator",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | testImplementation(
30 | project(":backstopper-reusable-tests-junit5"),
31 | project(":testonly:testonly-spring-webmvc-reusable-test-support"),
32 | "org.junit.jupiter:junit-jupiter:$junit5Version",
33 | "org.mockito:mockito-core:$mockitoVersion",
34 | "org.assertj:assertj-core:$assertJVersion",
35 | "io.rest-assured:rest-assured",
36 | )
37 | }
38 |
39 | // We're just running tests, not trying to stand up a real Springboot 3 server from gradle.
40 | // Disable the bootJar task so gradle doesn't fall over.
41 | bootJar.enabled = false
42 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webmvc-reusable-test-support/src/test/java/jsr303convention/ApplicationJsr303AnnotationTroller.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.internal.util.Pair;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.AnnotatedElement;
8 | import java.util.List;
9 | import java.util.function.Predicate;
10 |
11 | /**
12 | * Extension of {@link ReflectionBasedJsr303AnnotationTrollerBase} used by {@link VerifyJsr303ContractTest} and
13 | * {@link VerifyStringConvertsToClassTypeAnnotationsAreValidTest}).
14 | */
15 | public final class ApplicationJsr303AnnotationTroller extends ReflectionBasedJsr303AnnotationTrollerBase {
16 |
17 | private static final ApplicationJsr303AnnotationTroller INSTANCE = new ApplicationJsr303AnnotationTroller();
18 |
19 | @SuppressWarnings("WeakerAccess")
20 | public static ApplicationJsr303AnnotationTroller getInstance() {
21 | return INSTANCE;
22 | }
23 |
24 | // Intentionally private - use {@code getInstance()} to retrieve the singleton instance of this class.
25 | private ApplicationJsr303AnnotationTroller() {
26 | super();
27 | }
28 |
29 | @Override
30 | protected List> ignoreAllAnnotationsAssociatedWithTheseProjectClasses() {
31 | return null;
32 | }
33 |
34 | @Override
35 | protected List>> specificAnnotationDeclarationExclusionsForProject() {
36 | return null;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/testonly/testonly-spring-webflux-reusable-test-support/src/test/java/jsr303convention/ApplicationJsr303AnnotationTroller.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.internal.util.Pair;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.AnnotatedElement;
8 | import java.util.List;
9 | import java.util.function.Predicate;
10 |
11 | /**
12 | * Extension of {@link ReflectionBasedJsr303AnnotationTrollerBase} used by {@link VerifyJsr303ContractTest} and
13 | * {@link VerifyStringConvertsToClassTypeAnnotationsAreValidTest}).
14 | */
15 | public final class ApplicationJsr303AnnotationTroller extends ReflectionBasedJsr303AnnotationTrollerBase {
16 |
17 | private static final ApplicationJsr303AnnotationTroller INSTANCE = new ApplicationJsr303AnnotationTroller();
18 |
19 | @SuppressWarnings("WeakerAccess")
20 | public static ApplicationJsr303AnnotationTroller getInstance() {
21 | return INSTANCE;
22 | }
23 |
24 | // Intentionally private - use {@code getInstance()} to retrieve the singleton instance of this class.
25 | private ApplicationJsr303AnnotationTroller() {
26 | super();
27 | }
28 |
29 | @Override
30 | protected List> ignoreAllAnnotationsAssociatedWithTheseProjectClasses() {
31 | return null;
32 | }
33 |
34 | @Override
35 | protected List>> specificAnnotationDeclarationExclusionsForProject() {
36 | return null;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/backstopper-spring-web-flux/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | dependencies {
4 | api(
5 | project(":backstopper-jackson"),
6 | project(":backstopper-spring-web"),
7 | )
8 | compileOnly(
9 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
10 | "org.springframework:spring-webflux:$spring6_0Version",
11 | "org.springframework:spring-context:$spring6_0Version",
12 | )
13 | testImplementation(
14 | project(":backstopper-core").sourceSets.test.output,
15 | project(":backstopper-custom-validators"),
16 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion",
17 | "junit:junit:$junitVersion",
18 | "org.mockito:mockito-core:$mockitoVersion",
19 | "ch.qos.logback:logback-classic:$logbackVersion",
20 | "org.assertj:assertj-core:$assertJVersion",
21 | "com.tngtech.java:junit-dataprovider:$junitDataproviderVersion",
22 | "io.rest-assured:rest-assured:$restAssuredVersion",
23 | // Pulling in commons-codec manually to avoid vulnerability warning coming from RestAssured transitive dep.
24 | "commons-codec:commons-codec:$commonsCodecVersion",
25 | "org.springframework.boot:spring-boot-starter-webflux:$springboot3_3Version",
26 | "jakarta.validation:jakarta.validation-api:$jakartaValidationVersion",
27 | "org.hibernate.validator:hibernate-validator:$hibernateValidatorVersion",
28 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/backstopper-spring-web-mvc/src/test/java/com/nike/backstopper/handler/spring/SpringApiExceptionHandlerUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.handler.spring;
2 |
3 | import com.nike.backstopper.apierror.testing.base.BaseSpringEnabledValidationTestCase;
4 | import com.nike.backstopper.apierror.testutil.BarebonesCoreApiErrorForTesting;
5 | import com.nike.backstopper.model.DefaultErrorContractDTO;
6 |
7 | import org.junit.Test;
8 | import org.springframework.web.servlet.ModelAndView;
9 |
10 | import java.util.Arrays;
11 |
12 | import static org.hamcrest.CoreMatchers.is;
13 | import static org.hamcrest.MatcherAssert.assertThat;
14 |
15 | /**
16 | * Tests the functionality of {@link com.nike.backstopper.handler.ApiExceptionHandlerUtils}.
17 | *
18 | * @author Nic Munroe
19 | */
20 | public class SpringApiExceptionHandlerUtilsTest extends BaseSpringEnabledValidationTestCase {
21 |
22 | @Test
23 | public void generateModelAndViewForErrorResponseShouldGenerateModelAndViewWithErrorContractAsOnlyModelObject() {
24 | DefaultErrorContractDTO
25 | erv = new DefaultErrorContractDTO("someRequestId", Arrays.asList(BarebonesCoreApiErrorForTesting.NO_ACCEPTABLE_REPRESENTATION,
26 | BarebonesCoreApiErrorForTesting.UNSUPPORTED_MEDIA_TYPE));
27 |
28 | ModelAndView mav = new SpringApiExceptionHandlerUtils().generateModelAndViewForErrorResponse(erv, -1, null, null, null);
29 | assertThat(mav.getModel().size(), is(1));
30 | assertThat(mav.getModel().values().iterator().next() == erv, is(true));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/samples/sample-spring-boot3-webmvc/build.gradle:
--------------------------------------------------------------------------------
1 | evaluationDependsOn(':')
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot3_3Version}")
9 | }
10 | }
11 |
12 | apply plugin: 'org.springframework.boot'
13 | apply plugin: "io.spring.dependency-management"
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | dependencies {
20 | implementation(
21 | project(":backstopper-spring-boot3-webmvc"),
22 | project(":backstopper-custom-validators"),
23 | "ch.qos.logback:logback-classic",
24 | "org.springframework.boot:spring-boot-dependencies:$springboot3_3Version",
25 | "org.springframework.boot:spring-boot-starter-web",
26 | "org.hibernate.validator:hibernate-validator",
27 | "org.glassfish.expressly:expressly:$glassfishExpresslyVersion",
28 | )
29 | compileOnly(
30 | "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
31 | )
32 | testImplementation(
33 | project(":backstopper-reusable-tests-junit5"),
34 | "org.junit.jupiter:junit-jupiter:$junit5Version",
35 | "org.mockito:mockito-core:$mockitoVersion",
36 | "org.assertj:assertj-core:$assertJVersion",
37 | "io.rest-assured:rest-assured",
38 | )
39 | }
40 |
41 | apply plugin: "application"
42 | application {
43 | setMainClass("com.nike.backstopper.springboot3webmvcsample.Main")
44 | }
45 |
46 | run {
47 | systemProperties(System.getProperties())
48 | }
49 |
--------------------------------------------------------------------------------
/backstopper-core/src/main/java/com/nike/backstopper/handler/listener/ApiExceptionHandlerListener.java:
--------------------------------------------------------------------------------
1 | package com.nike.backstopper.handler.listener;
2 |
3 | import com.nike.backstopper.apierror.ApiError;
4 | import com.nike.backstopper.handler.ApiExceptionHandlerBase;
5 |
6 | /**
7 | * An exception handler listener intended to be used by {@link ApiExceptionHandlerBase}. A concrete implementation of
8 | * this will look for exceptions matching some criteria and return a {@link ApiExceptionHandlerListenerResult}
9 | * representing either an "I want to handle this exception by using these {@link ApiError}s and this logging info"
10 | * result or an "I don't want to handle this exception" result.
11 | *
12 | * @author Nic Munroe
13 | */
14 | public interface ApiExceptionHandlerListener {
15 |
16 | /**
17 | * @return A {@link ApiExceptionHandlerListenerResult} representing whether or not this instance wishes to handle
18 | * the exception. If {@link ApiExceptionHandlerListenerResult#shouldHandleResponse} is true then
19 | * {@link ApiExceptionHandlerBase} should handle the exception by using
20 | * {@link ApiExceptionHandlerListenerResult#errors} for the info returned to the client and should log the
21 | * info from {@link ApiExceptionHandlerListenerResult#extraDetailsForLogging}. Otherwise if
22 | * {@link ApiExceptionHandlerListenerResult#shouldHandleResponse} is false then
23 | * {@link ApiExceptionHandlerBase} should move on to the next listener.
24 | */
25 | ApiExceptionHandlerListenerResult shouldHandleException(Throwable ex);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/samples/sample-spring-boot3-webflux/src/test/java/jsr303convention/VerifyStringConvertsToClassTypeAnnotationsAreValidTest.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.backstopper.apierror.contract.jsr303convention.VerifyEnumsReferencedByStringConvertsToClassTypeJsr303AnnotationsAreJacksonCaseInsensitiveTest;
5 | import com.nike.backstopper.validation.constraints.StringConvertsToClassType;
6 |
7 | /**
8 | * Makes sure that any Enums referenced by {@link StringConvertsToClassType} JSR 303 annotations are case insensitive if
9 | * they are marked with {@link StringConvertsToClassType#allowCaseInsensitiveEnumMatch()} set to true.
10 | *
11 | *
You can exclude annotation declarations (e.g. for unit test classes that are intended to violate the naming
12 | * convention) by making sure that the {@link ApplicationJsr303AnnotationTroller#ignoreAllAnnotationsAssociatedWithTheseProjectClasses()}
13 | * and {@link ApplicationJsr303AnnotationTroller#specificAnnotationDeclarationExclusionsForProject()} methods return
14 | * what you need, but you should not exclude any annotations in production code under normal circumstances.
15 | *
16 | * @author Nic Munroe
17 | */
18 | public class VerifyStringConvertsToClassTypeAnnotationsAreValidTest
19 | extends VerifyEnumsReferencedByStringConvertsToClassTypeJsr303AnnotationsAreJacksonCaseInsensitiveTest {
20 |
21 | @Override
22 | protected ReflectionBasedJsr303AnnotationTrollerBase getAnnotationTroller() {
23 | return ApplicationJsr303AnnotationTroller.getInstance();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/sample-spring-boot3-webmvc/src/test/java/jsr303convention/VerifyStringConvertsToClassTypeAnnotationsAreValidTest.java:
--------------------------------------------------------------------------------
1 | package jsr303convention;
2 |
3 | import com.nike.backstopper.apierror.contract.jsr303convention.ReflectionBasedJsr303AnnotationTrollerBase;
4 | import com.nike.backstopper.apierror.contract.jsr303convention.VerifyEnumsReferencedByStringConvertsToClassTypeJsr303AnnotationsAreJacksonCaseInsensitiveTest;
5 | import com.nike.backstopper.validation.constraints.StringConvertsToClassType;
6 |
7 | /**
8 | * Makes sure that any Enums referenced by {@link StringConvertsToClassType} JSR 303 annotations are case insensitive if
9 | * they are marked with {@link StringConvertsToClassType#allowCaseInsensitiveEnumMatch()} set to true.
10 | *
11 | *