From 2c75cd99ce73e60eb911043dfe1df0ab7987d352 Mon Sep 17 00:00:00 2001 From: Anastasios Ioannidis Date: Thu, 10 Aug 2023 14:55:38 +0300 Subject: [PATCH 001/135] JAVA-13321 Added new gateway module to existing microservices e-book --- .../gateway-2/README-OAuth.md | 40 + .../gateway-2/README.md | 13 + .../gateway-2/baeldung-realm.json | 2186 +++++++++++++++++ .../spring-cloud-bootstrap/gateway-2/pom.xml | 194 ++ .../CustomFiltersGatewayApplication.java | 15 + .../gatewayapp/config/WebClientConfig.java | 16 + .../ChainRequestGatewayFilterFactory.java | 89 + .../LoggingGatewayFilterFactory.java | 85 + .../ModifyRequestGatewayFilterFactory.java | 92 + .../ModifyResponseGatewayFilterFactory.java | 48 + .../ScrubResponseGatewayFilterFactory.java | 110 + .../global/FirstPreLastPostGlobalFilter.java | 31 + .../global/LoggingGlobalFilterProperties.java | 47 + .../LoggingGlobalFiltersConfigurations.java | 25 + .../global/LoggingGlobalPreFilter.java | 22 + .../routes/ServiceRouteConfiguration.java | 28 + .../SecondServiceApplication.java | 15 + .../web/SecondServiceRestController.java | 18 + .../service/ServiceApplication.java | 15 + .../service/web/ServiceRestController.java | 22 + .../CustomPredicatesApplication.java | 15 + .../config/CustomPredicatesConfig.java | 43 + .../GoldenCustomerRoutePredicateFactory.java | 102 + .../service/GoldenCustomerService.java | 26 + .../IntroductionGatewayApplication.java | 15 + .../oauth/backend/QuotesApplication.java | 44 + .../oauth/backend/domain/Quote.java | 35 + .../oauth/backend/web/QuoteApi.java | 34 + .../ResourceServerGatewayApplication.java | 13 + .../KeycloakReactiveTokenInstrospector.java | 65 + .../rewrite/URLRewriteGatewayApplication.java | 25 + .../rewrite/routes/DynamicRewriteRoute.java | 43 + .../WebFilterGatewayApplication.java | 15 + .../config/ModifyBodyRouteConfig.java | 49 + .../RequestRateLimiterResolverConfig.java | 16 + .../resources/application-customroutes.yml | 26 + .../main/resources/application-nosecurity.yml | 8 + .../resources/application-oauth-client.yml | 26 + .../resources/application-resource-server.yml | 19 + .../src/main/resources/application-scrub.yml | 12 + .../resources/application-url-rewrite.yml | 11 + .../main/resources/application-webfilters.yml | 102 + .../src/main/resources/application.yml | 4 + ...ustomfilters-global-application.properties | 19 + .../introduction-application.properties | 7 + .../gateway-2/src/main/resources/logback.xml | 13 + .../resources/quotes-application.properties | 12 + .../secondservice-application.properties | 1 + .../resources/service-application.properties | 1 + .../gatewayapp/CustomFiltersLiveTest.java | 112 + ...bResponseGatewayFilterFactoryUnitTest.java | 61 + .../ScrubResponseGatewayFilterLiveTest.java | 135 + .../gatewayapp/utils/LoggerListAppender.java | 25 + .../SecondServiceIntegrationTest.java | 28 + .../secondservice/SpringContextTest.java | 12 + .../service/ServiceIntegrationTest.java | 31 + .../service/SpringContextTest.java | 12 + .../CustomPredicatesApplicationLiveTest.java | 67 + .../introduction/SpringContextTest.java | 15 + .../URLRewriteGatewayApplicationLiveTest.java | 109 + .../RedisWebFilterFactoriesLiveTest.java | 64 + .../WebFilterFactoriesLiveTest.java | 136 + .../OAuth_Gateway.postman_collection.json | 203 ++ .../src/test/resources/logback-test.xml | 17 + .../spring-cloud-bootstrap/pom.xml | 1 + 65 files changed, 4940 insertions(+) create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json create mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md new file mode 100644 index 0000000000..c186114589 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md @@ -0,0 +1,40 @@ +# OAuth Test Setup + +In order to test the OAuth-secured gateway configurations, please follow the steps below + +## Keycloak setup + +1. Clone or download the https://github.com/Baeldung/spring-security-oauth project +2. Replace the file `oauth-rest/oauth-authorization-server/src/main/resources/baeldung-realm.json` + with the one provider here +3. Go to the oauth-rest/oauth-authorization-server folder and use maven to build the project +4. Run the Keycloack service with `mvn spring-boot:run` +5. Once Keycloak is up and running, go to `http://localhost:8083/auth/admin/master/console/#/realms/baeldung` and + log in with using `bael-admin/pass` as credentials +6. Create two test users, so that one belongs to the *Golden Customers* group and the other doesn't. + +## Quotes backend + +Use the provided maven profile: + +``` +$ mvn spring-boot:run -Pquotes-application +``` + +## Gateway as Resource Server + +Use the provided maven profile: + +``` +$ mvn spring-boot:run -Pgateway-as-resource-server +``` + +## Gateway as OAuth 2.0 Client + +Use the provided maven profile: + +``` +$ mvn spring-boot:run -Pgateway-as-oauth-client +``` + + diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md new file mode 100644 index 0000000000..80315040c9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md @@ -0,0 +1,13 @@ +## Spring Cloud Gateway + +This module contains articles about Spring Cloud Gateway + +### Relevant Articles: + +- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) +- [Writing Custom Spring Cloud Gateway Filters](https://www.baeldung.com/spring-cloud-custom-gateway-filters) +- [Spring Cloud Gateway Routing Predicate Factories](https://www.baeldung.com/spring-cloud-gateway-routing-predicate-factories) +- [Spring Cloud Gateway WebFilter Factories](https://www.baeldung.com/spring-cloud-gateway-webfilter-factories) +- [Using Spring Cloud Gateway with OAuth 2.0 Patterns](https://www.baeldung.com/spring-cloud-gateway-oauth2) +- [URL Rewriting With Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-url-rewriting) +- [Processing the Response Body in Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-response-body) diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json new file mode 100644 index 0000000000..4dad262568 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json @@ -0,0 +1,2186 @@ +{ + "id": "baeldung", + "realm": "baeldung", + "notBefore": 0, + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "2f721e46-398b-43ff-845f-3c747f1f69f5", + "name": "standard", + "description": "Standard customer", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + }, + { + "id": "b8b1cb49-c953-4cb0-acea-62b24c4b6d30", + "name": "silver", + "description": "Silver customer", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + }, + { + "id": "f44f5ba9-2393-4d2a-b581-81cf8dd7f245", + "name": "gold", + "description": "Gold customers", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + }, + { + "id": "3b6109f5-6e5a-4578-83c3-791ec3e2bf9e", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + }, + { + "id": "0dd6a8c7-d669-4941-9ea1-521980e9c53f", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + }, + { + "id": "ca962095-7f9b-49e2-a190-e391a0d4b704", + "name": "user", + "composite": false, + "clientRole": false, + "containerId": "baeldung", + "attributes": {} + } + ], + "client": { + "newClient": [], + "realm-management": [ + { + "id": "5d00243f-ceec-4b0c-995e-d86d5b8a0ae6", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "941612de-bd85-47a5-8dfa-37c270dde28c", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "5ea9810d-63cc-4277-9b32-ba8a3d3c6091", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "8b7b0dd8-350b-473e-b8cd-8acad34f1358", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "0f8e5ee8-b014-4b7c-9b69-50f46abcba5f", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "911b1489-9383-4734-b134-bf49bf992ce9", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "5d48274c-bd6b-4c26-ad54-f1a2254beac0", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "3ea43b64-316f-4693-8346-9ee78b24adaf", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "49735614-96ec-49b2-98fe-3af9bcd1a33a", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "e8f8c3cc-0ff1-4f72-a271-db6821a3cdb6", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "387418b1-4f80-4b00-b9dd-805ca041f805", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "427c27d4-521a-464b-a0df-16d7f537e8d5", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "view-clients", + "view-authorization", + "query-groups", + "manage-realm", + "query-clients", + "manage-clients", + "view-realm", + "manage-identity-providers", + "create-client", + "manage-users", + "view-identity-providers", + "query-users", + "query-realms", + "view-users", + "impersonation", + "manage-authorization", + "manage-events", + "view-events" + ] + } + }, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "a574cf01-03e4-4573-ab9e-276d13a1ce8d", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "c3a253a8-a1b6-4d38-9677-f728f32482ad", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "f3cb93da-273e-419a-b2f4-93f09896abcf", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "6eedf2b7-50ef-4495-a89b-54aef751b7fa", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "0332e99b-3dfc-4193-9e13-5728f8f3e6d6", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "b690cb9c-0f4a-4be5-ade0-b40443d8149d", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + }, + { + "id": "aac3def5-f193-4a6c-9065-1667a0746a8a", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", + "attributes": {} + } + ], + "security-admin-console": [], + "quotes-client": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "397b5703-4c81-48fd-a24c-a7e8177ef657", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "4b9609f0-48d1-4e71-9381-2ecec08616f9", + "attributes": {} + } + ], + "account": [ + { + "id": "8daa8096-d14e-4d1c-ad1f-83f822016aa1", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + }, + { + "id": "15f0d8be-932b-4565-8ad0-e8aa170093dd", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + }, + { + "id": "c5aa697c-bf87-47c6-bd94-9121b72420b9", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + }, + { + "id": "f0b3bbe4-aec1-4227-b9d3-2c314d612a04", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + }, + { + "id": "948269c7-a69c-4c82-a7f3-88868713dfd9", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + }, + { + "id": "aed18201-2433-4998-8fa3-0979b0b31c10", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "635c3314-f15f-4c02-bcb7-8739fd4c21b7", + "name": "golden_customers", + "path": "/golden_customers", + "attributes": {}, + "realmRoles": [ + "gold" + ], + "clientRoles": {}, + "subGroups": [] + }, + { + "id": "279c5ec4-0588-4884-91c1-2697ed5c9826", + "name": "silver_customers", + "path": "/silver_customers", + "attributes": {}, + "realmRoles": [ + "silver" + ], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRoles": [ + "uma_authorization", + "offline_access" + ], + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/baeldung/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "defaultRoles": [ + "manage-account", + "view-profile" + ], + "redirectUris": [ + "/realms/baeldung/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "8209784b-8540-43c2-aece-241acf12ea5a", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/baeldung/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/realms/baeldung/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "58395b96-1718-4787-8f92-74577e2bfc30", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "13d76feb-d762-4409-bb84-7a75bc395a61", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4b9609f0-48d1-4e71-9381-2ecec08616f9", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "b88ce206-63d6-43b6-87c9-ea09d8c02f32", + "clientId": "newClient", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "http://localhost:8082/new-client/login/oauth2/code/custom", + "http://localhost:8089/", + "http://localhost:8089/auth/redirect/" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "saml_force_name_id_format": "false", + "saml.client.signature": "false", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "role_list", + "profile" + ], + "optionalClientScopes": [ + "web-origins", + "address", + "read", + "phone", + "roles", + "offline_access", + "microprofile-jwt", + "write", + "email" + ] + }, + { + "id": "5898f71f-b91e-4c3f-9c86-48de0e8665c4", + "clientId": "quotes-client", + "name": "Quotes Client", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "0e082231-a70d-48e8-b8a5-fbfb743041b6", + "redirectUris": [ + "http://localhost:8082/*", + "http://localhost:8087/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.multivalued.roles": "false", + "saml.force.post.binding": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "saml_force_name_id_format": "false", + "saml.client.signature": "false", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "008d32b5-ea7b-4739-89af-e90fe137bda9", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "6a4bfbd0-576d-4778-af56-56f876647355", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "8e358d2f-b085-4243-8e6e-c175431e5eeb", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/baeldung/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/admin/baeldung/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "9cfca9ee-493d-4b5e-8170-2d364149de59", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "77c7e29d-1a22-4419-bbfb-4a62bb033449", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "94e1879d-b49e-4178-96e0-bf8d7f32c160", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "b3526ac1-10e2-4344-8621-9c5a0853e97a", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "d30270dc-baa6-455a-8ff6-ddccf8a78d86", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "f5b1684d-e479-4134-8578-457fa64717da", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "c658ae14-e96a-4745-b21b-2ed5c4c63f5f", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "959521bc-5ffd-465b-95f2-5b0c20d1909c", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "07b8550c-b298-4cce-9ffb-900182575b76", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "569b3d44-4ecd-4768-a58c-70ff38f4b4fe", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "a3e7b19d-df6c-437e-9eea-06fec1becb2f", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "72a070f7-4363-4c88-8153-6fd2d12b9b04", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "24b42c6d-a93c-4aa1-9a03-2a2b55954c13", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "ba8c9950-fd0b-4434-8be6-b58456d7b6d4", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "0a9ddd71-309c-40f0-8ea6-a0791070c6ed", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "fbf53bbd-1ad0-4bf8-8030-50f81696d8ee", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "423be2cd-42c0-462e-9030-18f9b28ff2d3", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "53eb9006-4b81-474a-8b60-80f775d54b63", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "4d8bc82a-eaeb-499e-8eb2-0f1dcbe91699", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "d3b25485-4042-419d-afff-cfd63a76e229", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "422cfa5a-f2f4-4f36-82df-91b47ae1ea50", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "3f2863c1-d98d-45b5-b08f-af9c4d9c10f8", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "c98c063d-eee4-41a0-9130-595afd709d1f", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "8dbed80a-d672-4185-8dda-4bba2a56ec83", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "5e5c690c-93cf-489d-a054-b109eab8911b", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "3b985202-af8a-42f1-ac5f-0966a404f5d7", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "6eafd1b3-7121-4919-ad1e-039fa58acc32", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "73cba925-8c31-443f-9601-b1514e6396c1", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "c1a2eb23-25c6-4be7-a791-bbdca99c83f7", + "name": "read", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true" + } + }, + { + "id": "18e141bf-dabe-4858-879c-dbc439cdead4", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "10cbe37f-0198-4d65-bc8a-bfe5ad8145d1", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "111ed87a-5fd3-4cee-96df-8dbfb88cfdc0", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "24924d8d-6071-4a93-b40f-326176cb335e", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "2f6a9bdf-3758-484c-996d-e4f93555559f", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "804d4798-d9a3-4fd3-8b28-d12142e8cb3d", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "51d49314-b511-43e0-9258-bfb873758a78", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "2b384cd0-9e85-4a87-8eeb-2b480b0587b7", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "c3e253fb-7361-47cf-9d4a-86245686fdf1", + "name": "write", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true" + } + } + ], + "defaultDefaultClientScopes": [ + "roles", + "role_list", + "web-origins", + "email", + "profile" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "84305f42-4b6d-4b0a-ac7c-53e406e3ac63", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "c7c38a95-744f-4558-a403-9cf692fe1944", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "365b2899-befe-4417-b89b-562650ec4446", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "81c32244-7921-43e9-9356-a3469259b78c", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "d09b2147-afea-4f7f-a49c-0aec7eee10de", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "41ffde1b-72a2-416f-87a7-94989e940dc0", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "76075388-2782-4656-a986-313493239a9f", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "3caaf57a-9cd7-48c1-b709-b40b887414f7", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "oidc-address-mapper", + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "d67a940a-52e4-44a5-9f69-6ffdd67a188f", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "48d40de3-6234-42e8-9449-f68f56abb54b", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "52ea1c5d-2a30-459f-b66a-249f298b32f8", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "b35b726e-c1cc-4a31-8670-8c858c088498", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Handle Existing Account - Alternatives - 0", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "b7cb4b8c-0064-4c6b-95ee-d7f50011bae7", + "alias": "Handle Existing Account - Alternatives - 0", + "description": "Subflow of Handle Existing Account with alternative executions", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "2576bf21-a516-4e22-8ed8-8a1a3d35c06a", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "Verify Existing Account by Re-authentication - auth-otp-form - Conditional", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "867b0355-c2b0-4f4e-b535-09406e2bc086", + "alias": "Verify Existing Account by Re-authentication - auth-otp-form - Conditional", + "description": "Flow to determine if the auth-otp-form authenticator should be used or not.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "52e45a6a-292f-4a34-9c02-7f97d9997a9c", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "identity-provider-redirector", + "requirement": "ALTERNATIVE", + "priority": 25, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "forms", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "ef818d24-fb06-418a-a093-16239068cb58", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-jwt", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-secret-jwt", + "requirement": "ALTERNATIVE", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-x509", + "requirement": "ALTERNATIVE", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "f7864004-be4b-40f2-8534-454981f09f98", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-password", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 30, + "flowAlias": "direct grant - direct-grant-validate-otp - Conditional", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "233225f2-78b0-4756-9568-a775ea7cc975", + "alias": "direct grant - direct-grant-validate-otp - Conditional", + "description": "Flow to determine if the direct-grant-validate-otp authenticator should be used or not.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "2787939c-3312-4d56-9d61-22a71947e154", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "c80ca473-6e65-4140-a9d1-035414546bfb", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "first broker login - Alternatives - 0", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "700a71e1-f176-432e-9e70-ccb06d539730", + "alias": "first broker login - Alternatives - 0", + "description": "Subflow of first broker login with alternative executions", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "13cd2ee9-8ebb-4651-8a9d-535d4020d889", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "forms - auth-otp-form - Conditional", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "80067ebf-72b9-4ba5-abc3-161dfdd53938", + "alias": "forms - auth-otp-form - Conditional", + "description": "Flow to determine if the auth-otp-form authenticator should be used or not.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "269354b1-7dd7-46ff-8a69-084cd2c7be80", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "c5fa64a0-e784-490f-8879-0e8a209e3636", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "requirement": "REQUIRED", + "priority": 10, + "flowAlias": "registration form", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "bc48f897-4d16-49a8-be70-183c7867e20a", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-profile-action", + "requirement": "REQUIRED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-password-action", + "requirement": "REQUIRED", + "priority": 50, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-recaptcha-action", + "requirement": "DISABLED", + "priority": 60, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "fddaba41-87b1-40d1-b147-f062c38e39ad", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-credential-email", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-password", + "requirement": "REQUIRED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "CONDITIONAL", + "priority": 40, + "flowAlias": "reset credentials - reset-otp - Conditional", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "6b9fa295-1eb4-48b0-a286-b17ebd6be7e1", + "alias": "reset credentials - reset-otp - Conditional", + "description": "Flow to determine if the reset-otp authenticator should be used or not.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "c890d4c4-e4e2-4618-b69d-8d30f8278965", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "2b02fbe4-e05e-4238-bb0e-04da7d4efd4e", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "07dd933b-ce95-4a7c-bd81-3efa24f9558c", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "clientOfflineSessionMaxLifespan": "0", + "clientSessionIdleTimeout": "0", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0" + }, + "keycloakVersion": "11.0.2", + "userManagedAccessAllowed": false +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml new file mode 100644 index 0000000000..dc42483dc5 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -0,0 +1,194 @@ + + + 4.0.0 + gateway-2 + spring-cloud-gateway + jar + + + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + org.springframework.cloud + spring-cloud-starter-circuitbreaker-reactor-resilience4j + + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + it.ozimov + embedded-redis + ${redis.version} + test + + + org.hibernate + hibernate-validator-cdi + ${hibernate-validator.version} + + + javax.validation + validation-api + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-devtools + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + + quotes-application + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.springcloudgateway.oauth.backend.QuotesApplication + + + + + + + gateway-as-resource-server + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.springcloudgateway.oauth.server.ResourceServerGatewayApplication + -Dspring.profiles.active=resource-server + + + + + + + gateway-as-oauth-client + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.springcloudgateway.oauth.server.ResourceServerGatewayApplication + -Dspring.profiles.active=oauth-client + + + + + + + gateway-url-rewrite + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.springcloudgateway.rewrite.URLRewriteGatewayApplication + -Dspring.profiles.active=url-rewrite + + + + + + + + + + + 6.0.2.Final + 0.7.2 + 9.19 + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java new file mode 100644 index 0000000000..fae25bb7cc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:customfilters-global-application.properties") +public class CustomFiltersGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(CustomFiltersGatewayApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java new file mode 100644 index 0000000000..0589d8c321 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebClientConfig { + + @Bean + WebClient client() { + return WebClient.builder() + .build(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java new file mode 100644 index 0000000000..f53b0a3c93 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java @@ -0,0 +1,89 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale.LanguageRange; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +@Component +public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFactory { + + final Logger logger = LoggerFactory.getLogger(ChainRequestGatewayFilterFactory.class); + + private final WebClient client; + + public ChainRequestGatewayFilterFactory(WebClient client) { + super(Config.class); + this.client = client; + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("languageServiceEndpoint", "defaultLanguage"); + } + + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + return client.get() + .uri(config.getLanguageServiceEndpoint()) + .exchange() + .flatMap(response -> { + return (response.statusCode() + .is2xxSuccessful()) ? response.bodyToMono(String.class) : Mono.just(config.getDefaultLanguage()); + }) + .map(LanguageRange::parse) + .map(range -> { + exchange.getRequest() + .mutate() + .headers(h -> h.setAcceptLanguage(range)); + + String allOutgoingRequestLanguages = exchange.getRequest() + .getHeaders() + .getAcceptLanguage() + .stream() + .map(r -> r.getRange()) + .collect(Collectors.joining(",")); + + logger.info("Chain Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages); + + return exchange; + }) + .flatMap(chain::filter); + + }; + } + + public static class Config { + private String languageServiceEndpoint; + private String defaultLanguage; + + public Config() { + } + + public String getLanguageServiceEndpoint() { + return languageServiceEndpoint; + } + + public void setLanguageServiceEndpoint(String languageServiceEndpoint) { + this.languageServiceEndpoint = languageServiceEndpoint; + } + + public String getDefaultLanguage() { + return defaultLanguage; + } + + public void setDefaultLanguage(String defaultLanguage) { + this.defaultLanguage = defaultLanguage; + } + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java new file mode 100644 index 0000000000..900d36cc02 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java @@ -0,0 +1,85 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.stereotype.Component; + +import reactor.core.publisher.Mono; + +@Component +public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory { + + final Logger logger = LoggerFactory.getLogger(LoggingGatewayFilterFactory.class); + + public static final String BASE_MSG = "baseMessage"; + public static final String PRE_LOGGER = "preLogger"; + public static final String POST_LOGGER = "postLogger"; + + public LoggingGatewayFilterFactory() { + super(Config.class); + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList(BASE_MSG, PRE_LOGGER, POST_LOGGER); + } + + @Override + public GatewayFilter apply(Config config) { + return new OrderedGatewayFilter((exchange, chain) -> { + if (config.isPreLogger()) + logger.info("Pre GatewayFilter logging: " + config.getBaseMessage()); + return chain.filter(exchange) + .then(Mono.fromRunnable(() -> { + if (config.isPostLogger()) + logger.info("Post GatewayFilter logging: " + config.getBaseMessage()); + })); + }, 1); + } + + public static class Config { + private String baseMessage; + private boolean preLogger; + private boolean postLogger; + + public Config() { + }; + + public Config(String baseMessage, boolean preLogger, boolean postLogger) { + super(); + this.baseMessage = baseMessage; + this.preLogger = preLogger; + this.postLogger = postLogger; + } + + public String getBaseMessage() { + return this.baseMessage; + } + + public boolean isPreLogger() { + return preLogger; + } + + public boolean isPostLogger() { + return postLogger; + } + + public void setBaseMessage(String baseMessage) { + this.baseMessage = baseMessage; + } + + public void setPreLogger(boolean preLogger) { + this.preLogger = preLogger; + } + + public void setPostLogger(boolean postLogger) { + this.postLogger = postLogger; + } + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java new file mode 100644 index 0000000000..5828f35a36 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java @@ -0,0 +1,92 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; + +@Component +public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory { + + final Logger logger = LoggerFactory.getLogger(ModifyRequestGatewayFilterFactory.class); + + public ModifyRequestGatewayFilterFactory() { + super(Config.class); + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("defaultLocale"); + } + + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + if (exchange.getRequest() + .getHeaders() + .getAcceptLanguage() + .isEmpty()) { + + String queryParamLocale = exchange.getRequest() + .getQueryParams() + .getFirst("locale"); + + Locale requestLocale = Optional.ofNullable(queryParamLocale) + .map(l -> Locale.forLanguageTag(l)) + .orElse(config.getDefaultLocale()); + + exchange.getRequest() + .mutate() + .headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale))); + } + + String allOutgoingRequestLanguages = exchange.getRequest() + .getHeaders() + .getAcceptLanguage() + .stream() + .map(range -> range.getRange()) + .collect(Collectors.joining(",")); + + logger.info("Modify request output - Request contains Accept-Language header: {}", allOutgoingRequestLanguages); + + ServerWebExchange modifiedExchange = exchange.mutate() + .request(originalRequest -> originalRequest.uri(UriComponentsBuilder.fromUri(exchange.getRequest() + .getURI()) + .replaceQueryParams(new LinkedMultiValueMap()) + .build() + .toUri())) + .build(); + + logger.info("Removed all query params: {}", modifiedExchange.getRequest() + .getURI()); + + return chain.filter(modifiedExchange); + }; + } + + public static class Config { + private Locale defaultLocale; + + public Config() { + } + + public Locale getDefaultLocale() { + return defaultLocale; + } + + public void setDefaultLocale(String defaultLocale) { + this.defaultLocale = Locale.forLanguageTag(defaultLocale); + }; + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java new file mode 100644 index 0000000000..f5efa69402 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java @@ -0,0 +1,48 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; + +import reactor.core.publisher.Mono; + +@Component +public class ModifyResponseGatewayFilterFactory extends AbstractGatewayFilterFactory { + + final Logger logger = LoggerFactory.getLogger(ModifyResponseGatewayFilterFactory.class); + + public ModifyResponseGatewayFilterFactory() { + super(Config.class); + } + + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + return chain.filter(exchange) + .then(Mono.fromRunnable(() -> { + ServerHttpResponse response = exchange.getResponse(); + + Optional.ofNullable(exchange.getRequest() + .getQueryParams() + .getFirst("locale")) + .ifPresent(qp -> { + String responseContentLanguage = response.getHeaders() + .getContentLanguage() + .getLanguage(); + + response.getHeaders() + .add("Bael-Custom-Language-Header", responseContentLanguage); + logger.info("Added custom header to Response"); + }); + })); + }; + } + + public static class Config { + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java new file mode 100644 index 0000000000..dbe9a9fb4f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java @@ -0,0 +1,110 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; + +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; + +import reactor.core.publisher.Mono; + +@Component +public class ScrubResponseGatewayFilterFactory extends AbstractGatewayFilterFactory { + + final Logger logger = LoggerFactory.getLogger(ScrubResponseGatewayFilterFactory.class); + private ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory; + + public ScrubResponseGatewayFilterFactory(ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory) { + super(Config.class); + this.modifyResponseBodyFilterFactory = modifyResponseBodyFilterFactory; + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("fields", "replacement"); + } + + + @Override + public GatewayFilter apply(Config config) { + + return modifyResponseBodyFilterFactory + .apply(c -> c.setRewriteFunction(JsonNode.class, JsonNode.class, new Scrubber(config))); + } + + public static class Config { + + private String fields; + private String replacement; + + + public String getFields() { + return fields; + } + public void setFields(String fields) { + this.fields = fields; + } + public String getReplacement() { + return replacement; + } + public void setReplacement(String replacement) { + this.replacement = replacement; + } + } + + + public static class Scrubber implements RewriteFunction { + private final Pattern fields; + private final String replacement; + + public Scrubber(Config config) { + this.fields = Pattern.compile(config.getFields()); + this.replacement = config.getReplacement(); + } + + @Override + public Publisher apply(ServerWebExchange t, JsonNode u) { + return Mono.just(scrubRecursively(u)); + } + + private JsonNode scrubRecursively(JsonNode u) { + if ( !u.isContainerNode()) { + return u; + } + + if ( u.isObject()) { + ObjectNode node = (ObjectNode)u; + node.fields().forEachRemaining((f) -> { + if ( fields.matcher(f.getKey()).matches() && f.getValue().isTextual()) { + f.setValue(TextNode.valueOf(replacement)); + } + else { + f.setValue(scrubRecursively(f.getValue())); + } + }); + } + else if ( u.isArray()) { + ArrayNode array = (ArrayNode)u; + for ( int i = 0 ; i < array.size() ; i++ ) { + array.set(i, scrubRecursively(array.get(i))); + } + } + + return u; + } + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java new file mode 100644 index 0000000000..687f3fe685 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java @@ -0,0 +1,31 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; + +import reactor.core.publisher.Mono; + +@Component +public class FirstPreLastPostGlobalFilter implements GlobalFilter, Ordered { + + final Logger logger = LoggerFactory.getLogger(FirstPreLastPostGlobalFilter.class); + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + logger.info("First Pre Global Filter"); + return chain.filter(exchange) + .then(Mono.fromRunnable(() -> { + logger.info("Last Post Global Filter"); + })); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java new file mode 100644 index 0000000000..4bf6453355 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java @@ -0,0 +1,47 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("logging.global") +public class LoggingGlobalFilterProperties { + + private boolean enabled; + private boolean requestHeaders; + private boolean requestBody; + private boolean responseHeaders; + private boolean responseBody; + + public boolean isEnabled() { + return enabled; + } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + public boolean isRequestHeaders() { + return requestHeaders; + } + public void setRequestHeaders(boolean requestHeaders) { + this.requestHeaders = requestHeaders; + } + public boolean isRequestBody() { + return requestBody; + } + public void setRequestBody(boolean requestBody) { + this.requestBody = requestBody; + } + public boolean isResponseHeaders() { + return responseHeaders; + } + public void setResponseHeaders(boolean responseHeaders) { + this.responseHeaders = responseHeaders; + } + public boolean isResponseBody() { + return responseBody; + } + public void setResponseBody(boolean responseBody) { + this.responseBody = responseBody; + } + + + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java new file mode 100644 index 0000000000..2dead8da3b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java @@ -0,0 +1,25 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import reactor.core.publisher.Mono; + +@Configuration +public class LoggingGlobalFiltersConfigurations { + + final Logger logger = LoggerFactory.getLogger(LoggingGlobalFiltersConfigurations.class); + + @Bean + public GlobalFilter postGlobalFilter() { + return (exchange, chain) -> { + return chain.filter(exchange) + .then(Mono.fromRunnable(() -> { + logger.info("Global Post Filter executed"); + })); + }; + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java new file mode 100644 index 0000000000..2bacf033db --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java @@ -0,0 +1,22 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; + +import reactor.core.publisher.Mono; + +@Component +public class LoggingGlobalPreFilter implements GlobalFilter { + + final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class); + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + logger.info("Global Pre Filter executed"); + return chain.filter(exchange); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java new file mode 100644 index 0000000000..17d4827d93 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java @@ -0,0 +1,28 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.routes; + +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; + +import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory; +import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory.Config; + +/** + * Note: We want to keep this as an example of configuring a Route with a custom filter + * + * This corresponds with the properties configuration we have + */ +// @Configuration +public class ServiceRouteConfiguration { + + @Bean + public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) { + + return builder.routes() + .route("service_route_java_config", r -> r.path("/service/**") + .filters(f -> f.rewritePath("/service(?/?.*)", "$\\{segment}") + .filter(loggingFactory.apply(new Config("My Custom Message", true, true)))) + .uri("http://localhost:8081")) + .build(); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java new file mode 100644 index 0000000000..b65d0efbd6 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.customfilters.secondservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:secondservice-application.properties") +public class SecondServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SecondServiceApplication.class, args); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java new file mode 100644 index 0000000000..1ac44ba6b1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java @@ -0,0 +1,18 @@ +package com.baeldung.springcloudgateway.customfilters.secondservice.web; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import reactor.core.publisher.Mono; + +@RestController +public class SecondServiceRestController { + + @GetMapping("/resource/language") + public Mono> getResource() { + return Mono.just(ResponseEntity.ok() + .body("es")); + + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java new file mode 100644 index 0000000000..1e2ffb63c2 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.customfilters.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:service-application.properties") +public class ServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ServiceApplication.class, args); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java new file mode 100644 index 0000000000..3ca09f6853 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java @@ -0,0 +1,22 @@ +package com.baeldung.springcloudgateway.customfilters.service.web; + +import java.util.Locale; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import reactor.core.publisher.Mono; + +@RestController +public class ServiceRestController { + + @GetMapping("/resource") + public Mono> getResource() { + return Mono.just(ResponseEntity.ok() + .header(HttpHeaders.CONTENT_LANGUAGE, Locale.ENGLISH.getLanguage()) + .body("Service Resource")); + + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java new file mode 100644 index 0000000000..e209b6cdf0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class CustomPredicatesApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(CustomPredicatesApplication.class) + .profiles("customroutes") + .run(args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java new file mode 100644 index 0000000000..ea58eb7e46 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java @@ -0,0 +1,43 @@ +package com.baeldung.springcloudgateway.custompredicates.config; + +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory; +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory.Config; +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +@Configuration +public class CustomPredicatesConfig { + + + @Bean + public GoldenCustomerRoutePredicateFactory goldenCustomer(GoldenCustomerService goldenCustomerService) { + return new GoldenCustomerRoutePredicateFactory(goldenCustomerService); + } + + + //@Bean + public RouteLocator routes(RouteLocatorBuilder builder, GoldenCustomerRoutePredicateFactory gf ) { + + return builder.routes() + .route("dsl_golden_route", r -> + r.predicate(gf.apply(new Config(true, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .route("dsl_common_route", r -> + r.predicate(gf.apply(new Config(false, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .build(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java new file mode 100644 index 0000000000..cb5c3a0b50 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java @@ -0,0 +1,102 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.factories; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import javax.validation.constraints.NotEmpty; + +import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; +import org.springframework.http.HttpCookie; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.server.ServerWebExchange; + +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +/** + * @author Philippe + * + */ +public class GoldenCustomerRoutePredicateFactory extends AbstractRoutePredicateFactory { + + private final GoldenCustomerService goldenCustomerService; + + public GoldenCustomerRoutePredicateFactory(GoldenCustomerService goldenCustomerService ) { + super(Config.class); + this.goldenCustomerService = goldenCustomerService; + } + + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("isGolden","customerIdCookie"); + } + + + @Override + public Predicate apply(Config config) { + + return (ServerWebExchange t) -> { + List cookies = t.getRequest() + .getCookies() + .get(config.getCustomerIdCookie()); + + boolean isGolden; + if ( cookies == null || cookies.isEmpty()) { + isGolden = false; + } + else { + String customerId = cookies.get(0).getValue(); + isGolden = goldenCustomerService.isGoldenCustomer(customerId); + } + + return config.isGolden()?isGolden:!isGolden; + }; + } + + + @Validated + public static class Config { + boolean isGolden = true; + + @NotEmpty + String customerIdCookie = "customerId"; + + + public Config() {} + + public Config( boolean isGolden, String customerIdCookie) { + this.isGolden = isGolden; + this.customerIdCookie = customerIdCookie; + } + + public boolean isGolden() { + return isGolden; + } + + public void setGolden(boolean value) { + this.isGolden = value; + } + + /** + * @return the customerIdCookie + */ + public String getCustomerIdCookie() { + return customerIdCookie; + } + + /** + * @param customerIdCookie the customerIdCookie to set + */ + public void setCustomerIdCookie(String customerIdCookie) { + this.customerIdCookie = customerIdCookie; + } + + + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java new file mode 100644 index 0000000000..82bf2e6ae9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java @@ -0,0 +1,26 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.service; + +import org.springframework.stereotype.Component; + +/** + * @author Philippe + * + */ +@Component +public class GoldenCustomerService { + + public boolean isGoldenCustomer(String customerId) { + + // TODO: Add some AI logic to check is this customer deserves a "golden" status ;^) + if ( "baeldung".equalsIgnoreCase(customerId)) { + return true; + } + else { + return false; + } + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java new file mode 100644 index 0000000000..d276597a6b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.introduction; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:introduction-application.properties") +public class IntroductionGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(IntroductionGatewayApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java new file mode 100644 index 0000000000..96daf8a73d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java @@ -0,0 +1,44 @@ +/** + * + */ +package com.baeldung.springcloudgateway.oauth.backend; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector; +import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; + +import com.baeldung.springcloudgateway.oauth.shared.KeycloakReactiveTokenInstrospector; + +/** + * @author Philippe + * + */ +@SpringBootApplication +@PropertySource("classpath:quotes-application.properties") +@EnableWebFluxSecurity +public class QuotesApplication { + + public static void main(String[] args) { + SpringApplication.run(QuotesApplication.class); + } + + + @Bean + public ReactiveOpaqueTokenIntrospector keycloakIntrospector(OAuth2ResourceServerProperties props) { + + NimbusReactiveOpaqueTokenIntrospector delegate = new NimbusReactiveOpaqueTokenIntrospector( + props.getOpaquetoken().getIntrospectionUri(), + props.getOpaquetoken().getClientId(), + props.getOpaquetoken().getClientSecret()); + + return new KeycloakReactiveTokenInstrospector(delegate); + } + + +} + diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java new file mode 100644 index 0000000000..042cfa63fa --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java @@ -0,0 +1,35 @@ +package com.baeldung.springcloudgateway.oauth.backend.domain; + + +public class Quote { + + private String symbol; + private double price; + + /** + * @return the symbol + */ + public String getSymbol() { + return symbol; + } + /** + * @param symbol the symbol to set + */ + public void setSymbol(String symbol) { + this.symbol = symbol; + } + /** + * @return the price + */ + public double getPrice() { + return price; + } + /** + * @param price the price to set + */ + public void setPrice(double price) { + this.price = price; + } + + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java new file mode 100644 index 0000000000..6d3721166c --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java @@ -0,0 +1,34 @@ +package com.baeldung.springcloudgateway.oauth.backend.web; + +import javax.annotation.PostConstruct; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.springcloudgateway.oauth.backend.domain.Quote; + +import reactor.core.publisher.Mono; + +@RestController +public class QuoteApi { + private static final GrantedAuthority GOLD_CUSTOMER = new SimpleGrantedAuthority("gold"); + + @GetMapping("/quotes/{symbol}") + public Mono getQuote(@PathVariable("symbol") String symbol, BearerTokenAuthentication auth ) { + + Quote q = new Quote(); + q.setSymbol(symbol); + + if ( auth.getAuthorities().contains(GOLD_CUSTOMER)) { + q.setPrice(10.0); + } + else { + q.setPrice(12.0); + } + return Mono.just(q); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java new file mode 100644 index 0000000000..1b85867f3b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.springcloudgateway.oauth.server; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; + +@SpringBootApplication +@EnableWebFluxSecurity +public class ResourceServerGatewayApplication { + public static void main(String[] args) { + SpringApplication.run(ResourceServerGatewayApplication.class,args); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java new file mode 100644 index 0000000000..e834e6934d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java @@ -0,0 +1,65 @@ +/** + * + */ +package com.baeldung.springcloudgateway.oauth.shared; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; +import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; +import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; + +import reactor.core.publisher.Mono; + +/** + * Custom ReactiveTokenIntrospector to map realm roles into Spring GrantedAuthorities + * + */ +public class KeycloakReactiveTokenInstrospector implements ReactiveOpaqueTokenIntrospector { + + private final ReactiveOpaqueTokenIntrospector delegate; + + public KeycloakReactiveTokenInstrospector(ReactiveOpaqueTokenIntrospector delegate) { + this.delegate = delegate; + } + + @Override + public Mono introspect(String token) { + + return delegate.introspect(token) + .map( this::mapPrincipal); + } + + protected OAuth2AuthenticatedPrincipal mapPrincipal(OAuth2AuthenticatedPrincipal principal) { + + return new DefaultOAuth2AuthenticatedPrincipal( + principal.getName(), + principal.getAttributes(), + extractAuthorities(principal)); + } + + protected Collection extractAuthorities(OAuth2AuthenticatedPrincipal principal) { + + // + Map> realm_access = principal.getAttribute("realm_access"); + List roles = realm_access.getOrDefault("roles", Collections.emptyList()); + List rolesAuthorities = roles.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + Set allAuthorities = new HashSet<>(); + allAuthorities.addAll(principal.getAuthorities()); + allAuthorities.addAll(rolesAuthorities); + + return allAuthorities; + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java new file mode 100644 index 0000000000..46541b4826 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java @@ -0,0 +1,25 @@ +/** + * + */ +package com.baeldung.springcloudgateway.rewrite; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.gateway.filter.GatewayFilter; + +import reactor.core.publisher.Mono; + +/** + * @author Baeldung + * + */ +@SpringBootApplication +public class URLRewriteGatewayApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(URLRewriteGatewayApplication.class) + .profiles("url-rewrite") + .run(args); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java new file mode 100644 index 0000000000..29d40d7021 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java @@ -0,0 +1,43 @@ +package com.baeldung.springcloudgateway.rewrite.routes; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.server.reactive.ServerHttpRequest; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl; + +import java.util.Random; + +@Configuration +@Profile("url-rewrite") +public class DynamicRewriteRoute { + + @Value("${rewrite.backend.uri}") + private String backendUri; + private static Random rnd = new Random(); + + @Bean + public RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) { + return builder.routes() + .route("dynamicRewrite", r -> + r.path("/v2/zip/**") + .filters(f -> f.filter((exchange, chain) -> { + ServerHttpRequest req = exchange.getRequest(); + addOriginalRequestUrl(exchange, req.getURI()); + String path = req.getURI().getRawPath(); + String newPath = path.replaceAll( + "/v2/zip/(?.*)", + "/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000))); + ServerHttpRequest request = req.mutate().path(newPath).build(); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI()); + return chain.filter(exchange.mutate().request(request).build()); + })) + .uri(backendUri)) + .build(); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java new file mode 100644 index 0000000000..9e212cc4bf --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.webfilters; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class WebFilterGatewayApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(WebFilterGatewayApplication.class) + .profiles("url-rewrite") + .run(args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java new file mode 100644 index 0000000000..7b6188b66a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java @@ -0,0 +1,49 @@ +package com.baeldung.springcloudgateway.webfilters.config; + +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; + +import reactor.core.publisher.Mono; + +@Configuration +public class ModifyBodyRouteConfig { + + @Bean + public RouteLocator routes(RouteLocatorBuilder builder) { + return builder.routes() + .route("modify_request_body", r -> r.path("/post") + .filters(f -> f.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, + (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri("https://httpbin.org")) + .build(); + } + + @Bean + public RouteLocator responseRoutes(RouteLocatorBuilder builder) { + return builder.routes() + .route("modify_response_body", r -> r.path("/put/**") + .filters(f -> f.modifyResponseBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, + (exchange, s) -> Mono.just(new Hello("New Body")))).uri("https://httpbin.org")) + .build(); + } + + static class Hello { + String message; + + public Hello() { } + + public Hello(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java new file mode 100644 index 0000000000..f80a742fa6 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java @@ -0,0 +1,16 @@ +package com.baeldung.springcloudgateway.webfilters.config; + +import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import reactor.core.publisher.Mono; + +@Configuration +public class RequestRateLimiterResolverConfig { + + @Bean + KeyResolver userKeyResolver() { + return exchange -> Mono.just("1"); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml new file mode 100644 index 0000000000..859aa60bda --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml @@ -0,0 +1,26 @@ +spring: + cloud: + gateway: + routes: + - id: golden_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - GoldenCustomer=true + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,true + - id: common_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - name: GoldenCustomer + args: + golden: false + customerIdCookie: customerId + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,false + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml new file mode 100644 index 0000000000..40a52ded0f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml @@ -0,0 +1,8 @@ +# Enable this profile to disable security +spring: + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + - org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration + - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration + - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml new file mode 100644 index 0000000000..b097c54eb1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml @@ -0,0 +1,26 @@ +server: + port: 8087 +spring: + cloud: + gateway: + redis: + enabled: false + routes: + - id: quotes + uri: http://localhost:8085 + predicates: + - Path=/quotes/** + filters: - TokenRelay= + security: + oauth2: + client: provider: keycloak: + issuer-uri: http://localhost:8083/auth/realms/baeldung + registration: quotes-client: + provider: keycloak + client-id: quotes-client + client-secret: 0e082231-a70d-48e8-b8a5-fbfb743041b6 + scope: - email + - profile + - roles + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml new file mode 100644 index 0000000000..14f713a04a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml @@ -0,0 +1,19 @@ +server: + port: 8086 +spring: + security: + oauth2: + resourceserver: + opaquetoken: + introspection-uri: http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/token/introspect + client-id: quotes-client + client-secret: 0e082231-a70d-48e8-b8a5-fbfb743041b6 + cloud: + gateway: + redis: + enabled: false + routes: + - id: quotes + uri: http://localhost:8085 + predicates: + - Path=/quotes/** diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml new file mode 100644 index 0000000000..da7dfea0a7 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml @@ -0,0 +1,12 @@ +spring: + cloud: + gateway: + routes: + - id: rewrite_with_scrub + uri: ${rewrite.backend.uri:http://example.com} + predicates: + - Path=/v1/customer/** + filters: + - RewritePath=/v1/customer/(?.*),/api/$\{segment} + - ScrubResponse=ssn,*** + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml new file mode 100644 index 0000000000..b2656151db --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml @@ -0,0 +1,11 @@ +spring: + cloud: + gateway: + routes: + - id: rewrite_v1 + uri: ${rewrite.backend.uri:http://example.com} + predicates: + - Path=/v1/customer/** + filters: + - RewritePath=/v1/customer/(?.*),/api/$\{segment} + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml new file mode 100644 index 0000000000..3348cbbba0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml @@ -0,0 +1,102 @@ +logging: + level: + org.springframework.cloud.gateway: INFO + reactor.netty.http.client: INFO + +spring: + redis: + host: localhost + port: 6379 + cloud: + gateway: + routes: + - id: request_header_route + uri: https://httpbin.org + predicates: + - Path=/get/** + filters: + - AddRequestHeader=My-Header-Good,Good + - AddRequestHeader=My-Header-Remove,Remove + - AddRequestParameter=var, good + - AddRequestParameter=var2, remove + - MapRequestHeader=My-Header-Good, My-Header-Bad + - MapRequestHeader=My-Header-Set, My-Header-Bad + - SetRequestHeader=My-Header-Set, Set + - RemoveRequestHeader=My-Header-Remove + - RemoveRequestParameter=var2 + - PreserveHostHeader + + - id: response_header_route + uri: https://httpbin.org + predicates: + - Path=/header/post/** + filters: + - AddResponseHeader=My-Header-Good,Good + - AddResponseHeader=My-Header-Set,Good + - AddResponseHeader=My-Header-Rewrite, password=12345678 + - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin + - AddResponseHeader=My-Header-Remove,Remove + - SetResponseHeader=My-Header-Set, Set + - RemoveResponseHeader=My-Header-Remove + - RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=*** + - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , + - StripPrefix=1 + + - id: path_route + uri: https://httpbin.org + predicates: + - Path=/new/post/** + filters: + - RewritePath=/new(?/?.*), $\{segment} + - SetPath=/post + + - id: redirect_route + uri: https://httpbin.org + predicates: + - Path=/fake/post/** + filters: + - RedirectTo=302, https://httpbin.org + + - id: status_route + uri: https://httpbin.org + predicates: + - Path=/delete/** + filters: + - SetStatus=401 + + - id: size_route + uri: https://httpbin.org + predicates: + - Path=/anything + filters: + - name: RequestSize + args: + maxSize: 5000000 + + - id: retry_test + uri: https://httpbin.org + predicates: + - Path=/status/502 + filters: + - name: Retry + args: + retries: 3 + statuses: BAD_GATEWAY + methods: GET,POST + backoff: + firstBackoff: 10ms + maxBackoff: 50ms + factor: 2 + basedOnPreviousValue: false + + - id: request_rate_limiter + uri: https://httpbin.org + predicates: + - Path=/redis/get/** + filters: + - StripPrefix=1 + - name: RequestRateLimiter + args: + redis-rate-limiter.replenishRate: 10 + redis-rate-limiter.burstCapacity: 5 + key-resolver: "#{@userKeyResolver}" \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml new file mode 100644 index 0000000000..a33bca2055 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml @@ -0,0 +1,4 @@ +logging: + level: + org.springframework.cloud.gateway: DEBUG + reactor.netty.http.client: DEBUG diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties new file mode 100644 index 0000000000..08421a0653 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties @@ -0,0 +1,19 @@ +spring.cloud.gateway.routes[0].id=service_route +spring.cloud.gateway.routes[0].uri=http://localhost:8081 +spring.cloud.gateway.routes[0].predicates[0]=Path=/service/** +spring.cloud.gateway.routes[0].filters[0]=RewritePath=/service(?/?.*), $\{segment} +spring.cloud.gateway.routes[0].filters[1]=Logging=My Custom Message, true, true +# Or, as an alternative: +#spring.cloud.gateway.routes[0].filters[1].name=Logging +#spring.cloud.gateway.routes[0].filters[1].args[baseMessage]=My Custom Message +#spring.cloud.gateway.routes[0].filters[1].args[preLogger]=true +#spring.cloud.gateway.routes[0].filters[1].args[postLogger]=true + +spring.cloud.gateway.routes[0].filters[2]=ModifyResponse +spring.cloud.gateway.routes[0].filters[3]=ModifyRequest=en +spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr + +management.endpoints.web.exposure.include=* + +server.port=80 + diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties new file mode 100644 index 0000000000..d7a6c4e072 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties @@ -0,0 +1,7 @@ +spring.cloud.gateway.routes[0].id=baeldung_route +spring.cloud.gateway.routes[0].uri=http://www.baeldung.com +spring.cloud.gateway.routes[0].predicates[0]=Path=/baeldung + +management.endpoints.web.exposure.include=* + +server.port=80 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties new file mode 100644 index 0000000000..48e8999b1b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties @@ -0,0 +1,12 @@ +server.port=8085 +# Disable gateway & redis as we don't need them in this application +spring.cloud.gateway.enabled=false +spring.cloud.gateway.redis.enabled=false + +# Resource server settings +spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/token/introspect +spring.security.oauth2.resourceserver.opaquetoken.client-id=quotes-client +spring.security.oauth2.resourceserver.opaquetoken.client-secret=0e082231-a70d-48e8-b8a5-fbfb743041b6 + + + diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties new file mode 100644 index 0000000000..3cf12afeb9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties @@ -0,0 +1 @@ +server.port=8082 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties new file mode 100644 index 0000000000..4d360de145 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties @@ -0,0 +1 @@ +server.port=8081 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java new file mode 100644 index 0000000000..f49f8c68b6 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java @@ -0,0 +1,112 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.assertj.core.api.Condition; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; + +import com.baeldung.springcloudgateway.customfilters.gatewayapp.utils.LoggerListAppender; + +import ch.qos.logback.classic.spi.ILoggingEvent; + +/** + * This test requires: + * * the service in com.baeldung.service running + * * the 'second service' in com.baeldung.secondservice running + * + */ +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class CustomFiltersLiveTest { + + @LocalServerPort + String port; + + @Autowired + private WebTestClient client; + + @BeforeEach + public void clearLogList() { + LoggerListAppender.clearEventList(); + client = WebTestClient.bindToServer() + .baseUrl("http://localhost:" + port) + .build(); + } + + @Test + public void whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { + ResponseSpec response = client.get() + .uri("/service/resource") + .exchange(); + + response.expectStatus() + .isOk() + .expectHeader() + .doesNotExist("Bael-Custom-Language-Header") + .expectBody(String.class) + .isEqualTo("Service Resource"); + + assertThat(LoggerListAppender.getEvents()) + // Global Pre Filter + .haveAtLeastOne(eventContains("Global Pre Filter executed")) + // Global Post Filter + .haveAtLeastOne(eventContains("Global Post Filter executed")) + // Global Pre and Post Filter + .haveAtLeastOne(eventContains("First Pre Global Filter")) + .haveAtLeastOne(eventContains("Last Post Global Filter")) + // Logging Filter Factory + .haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message")) + .haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message")) + // Modify Request + .haveAtLeastOne(eventContains("Modify request output - Request contains Accept-Language header:")) + .haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale")) + // Modify Response + .areNot(eventContains("Added custom header to Response")) + // Chain Request + .haveAtLeastOne(eventContains("Chain Request output - Request contains Accept-Language header:")); + } + + @Test + public void givenRequestWithLocaleQueryParam_whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { + ResponseSpec response = client.get() + .uri("/service/resource?locale=en") + .exchange(); + + response.expectStatus() + .isOk() + .expectHeader() + .exists("Bael-Custom-Language-Header") + .expectBody(String.class) + .isEqualTo("Service Resource"); + + assertThat(LoggerListAppender.getEvents()) + // Modify Response + .haveAtLeastOne(eventContains("Added custom header to Response")) + .haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale")); + } + + /** + * This condition will be successful if the event contains a substring + */ + private Condition eventContains(String substring) { + return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() + .contains(substring))), String.format("entry with message '%s'", substring)); + } + + /** + * This condition will be successful if the event contains a substring, but not another one + */ + private Condition eventContainsExcept(String substring, String except) { + return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() + .contains(substring) + && !entry.getFormattedMessage() + .contains(except))), + String.format("entry with message '%s'", substring)); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java new file mode 100644 index 0000000000..667aabaddc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Config; +import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Scrubber; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import reactor.core.publisher.Mono; + +class ScrubResponseGatewayFilterFactoryUnitTest { + + private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" + + " \"name\" : \"John Doe\",\r\n" + + " \"ssn\" : \"123-45-9999\",\r\n" + + " \"account\" : \"9999888877770000\"\r\n" + + "}"; + + + @Test + void givenJsonWithFieldsToScrub_whenApply_thenScrubFields() throws Exception{ + + JsonFactory jf = new JsonFactory(new ObjectMapper()); + JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); + JsonNode root = parser.readValueAsTree(); + + Config config = new Config(); + config.setFields("ssn|account"); + config.setReplacement("*"); + Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); + + JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); + assertNotNull(scrubbed); + assertEquals("*", scrubbed.get("ssn").asText()); + } + + @Test + void givenJsonWithoutFieldsToScrub_whenApply_theBodUnchanged() throws Exception{ + + JsonFactory jf = new JsonFactory(new ObjectMapper()); + JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); + JsonNode root = parser.readValueAsTree(); + + Config config = new Config(); + config.setFields("xxxx"); + config.setReplacement("*"); + Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); + + JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); + assertNotNull(scrubbed); + assertNotEquals("*", scrubbed.get("ssn").asText()); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java new file mode 100644 index 0000000000..8906af774e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java @@ -0,0 +1,135 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.Collections; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.sun.net.httpserver.HttpServer; + +import reactor.netty.http.client.HttpClient; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class ScrubResponseGatewayFilterLiveTest { + + private static Logger log = LoggerFactory.getLogger(ScrubResponseGatewayFilterLiveTest.class); + + private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" + + " \"name\" : \"John Doe\",\r\n" + + " \"ssn\" : \"123-45-9999\",\r\n" + + " \"account\" : \"9999888877770000\"\r\n" + + "}"; + + private static final String JSON_WITH_SCRUBBED_FIELDS = "{\r\n" + + " \"name\" : \"John Doe\",\r\n" + + " \"ssn\" : \"*\",\r\n" + + " \"account\" : \"9999888877770000\"\r\n" + + "}"; + + @LocalServerPort + String port; + + @Autowired + private WebTestClient client; + + @Autowired HttpServer server; + + @Test + public void givenRequestToScrubRoute_thenResponseScrubbed() { + + client.get() + .uri("/scrub") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus() + .is2xxSuccessful() + .expectHeader() + .contentType(MediaType.APPLICATION_JSON) + .expectBody() + .json(JSON_WITH_SCRUBBED_FIELDS); + } + + + @TestConfiguration + public static class TestRoutesConfiguration { + + + @Bean + public RouteLocator scrubSsnRoute(RouteLocatorBuilder builder, ScrubResponseGatewayFilterFactory scrubFilterFactory, SetPathGatewayFilterFactory pathFilterFactory, HttpServer server ) { + + log.info("[I92] Creating scrubSsnRoute..."); + + int mockServerPort = server.getAddress().getPort(); + ScrubResponseGatewayFilterFactory.Config config = new ScrubResponseGatewayFilterFactory.Config(); + config.setFields("ssn"); + config.setReplacement("*"); + + SetPathGatewayFilterFactory.Config pathConfig = new SetPathGatewayFilterFactory.Config(); + pathConfig.setTemplate("/customer"); + + return builder.routes() + .route("scrub_ssn", + r -> r.path("/scrub") + .filters( + f -> f + .filter(scrubFilterFactory.apply(config)) + .filter(pathFilterFactory.apply(pathConfig))) + .uri("http://localhost:" + mockServerPort )) + .build(); + } + + @Bean + public SecurityWebFilterChain testFilterChain(ServerHttpSecurity http ) { + + // @formatter:off + return http.authorizeExchange() + .anyExchange() + .permitAll() + .and() + .build(); + // @formatter:on + } + + @Bean + public HttpServer mockServer() throws IOException { + + log.info("[I48] Starting mock server..."); + + HttpServer server = HttpServer.create(new InetSocketAddress(0),0); + server.createContext("/customer", (exchange) -> { + exchange.getResponseHeaders().set("Content-Type", "application/json"); + + byte[] response = JSON_WITH_FIELDS_TO_SCRUB.getBytes("UTF-8"); + exchange.sendResponseHeaders(200,response.length); + exchange.getResponseBody().write(response); + }); + + server.setExecutor(null); + server.start(); + + log.info("[I65] Mock server started. port={}", server.getAddress().getPort()); + return server; + } + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java new file mode 100644 index 0000000000..8e113b417b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java @@ -0,0 +1,25 @@ +package com.baeldung.springcloudgateway.customfilters.gatewayapp.utils; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +public class LoggerListAppender extends AppenderBase { + + static private List events = new ArrayList<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + events.add(eventObject); + } + + public static List getEvents() { + return events; + } + + public static void clearEventList() { + events.clear(); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java new file mode 100644 index 0000000000..f4b3d0f00d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java @@ -0,0 +1,28 @@ +package com.baeldung.springcloudgateway.customfilters.secondservice; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.springcloudgateway.customfilters.secondservice.web.SecondServiceRestController; + +@WebFluxTest(controllers = SecondServiceRestController.class, + excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) +public class SecondServiceIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @Test + public void whenResourceLanguageEndpointCalled_thenRetrievesSpanishLanguageString() throws Exception { + this.webClient.get() + .uri("/resource/language") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("es"); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java new file mode 100644 index 0000000000..eaf94c0a42 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java @@ -0,0 +1,12 @@ +package com.baeldung.springcloudgateway.customfilters.secondservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = SecondServiceApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java new file mode 100644 index 0000000000..9990cd003c --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java @@ -0,0 +1,31 @@ +package com.baeldung.springcloudgateway.customfilters.service; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.http.HttpHeaders; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.springcloudgateway.customfilters.service.web.ServiceRestController; + +@WebFluxTest(controllers = ServiceRestController.class, + excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) +public class ServiceIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @Test + public void whenResourceEndpointCalled_thenRetrievesResourceStringWithContentLanguageHeader() throws Exception { + this.webClient.get() + .uri("/resource") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals(HttpHeaders.CONTENT_LANGUAGE, "en") + .expectBody(String.class) + .isEqualTo("Service Resource"); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java new file mode 100644 index 0000000000..2a9b322d5e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java @@ -0,0 +1,12 @@ +package com.baeldung.springcloudgateway.customfilters.service; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = ServiceApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java new file mode 100644 index 0000000000..d9988ceb5e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java @@ -0,0 +1,67 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Before; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +/** + * This test requires + */ +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("customroutes") +public class CustomPredicatesApplicationLiveTest { + + @LocalServerPort + String serverPort; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void givenNormalCustomer_whenCallHeadersApi_thenResponseForNormalCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + ResponseEntity response = restTemplate.getForEntity(url, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("false"); + + } + + @Test + void givenGoldenCustomer_whenCallHeadersApi_thenResponseForGoldenCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + RequestEntity request = RequestEntity + .get(URI.create(url)) + .header("Cookie", "customerId=baeldung") + .build(); + + ResponseEntity response = restTemplate.exchange(request, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("true"); + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java new file mode 100644 index 0000000000..1550265f22 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.introduction; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.springcloudgateway.introduction.IntroductionGatewayApplication; + + +@SpringBootTest(classes = IntroductionGatewayApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java new file mode 100644 index 0000000000..41fe37045c --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java @@ -0,0 +1,109 @@ +package com.baeldung.springcloudgateway.rewrite; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.OutputStream; +import java.net.InetSocketAddress; + +import org.junit.AfterClass; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.sun.net.httpserver.HttpServer; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles({ "nosecurity", "url-rewrite" }) +class URLRewriteGatewayApplicationLiveTest { + + // NOTE for Eclipse users: By default, Eclipse will complain about com.sun.** classes. + // To solve this issue, follow instructions available at the : + // https://stackoverflow.com/questions/13155734/eclipse-cant-recognize-com-sun-net-httpserver-httpserver-package + private static HttpServer mockServer; + private static Logger log = LoggerFactory.getLogger(URLRewriteGatewayApplicationLiveTest.class); + + // Create a running HttpServer that echoes back the request URL. + private static HttpServer startTestServer() { + + try { + log.info("[I26] Starting mock server"); + mockServer = HttpServer.create(); + mockServer.bind(new InetSocketAddress(0), 0); + mockServer.createContext("/api", (xchg) -> { + String uri = xchg.getRequestURI() + .toString(); + log.info("[I23] Backend called: uri={}", uri); + xchg.getResponseHeaders() + .add("Content-Type", "text/plain"); + xchg.sendResponseHeaders(200, 0); + OutputStream os = xchg.getResponseBody(); + os.write(uri.getBytes()); + os.flush(); + os.close(); + }); + + mockServer.start(); + InetSocketAddress localAddr = mockServer.getAddress(); + log.info("[I36] mock server started: local address={}", localAddr); + + return mockServer; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + + // TIP: https://www.baeldung.com/spring-dynamicpropertysource + @DynamicPropertySource + static void registerBackendServer(DynamicPropertyRegistry registry) { + registry.add("rewrite.backend.uri", () -> { + HttpServer s = startTestServer(); + return "http://localhost:" + s.getAddress().getPort(); + }); + } + + @AfterClass + public static void stopMockBackend() throws Exception { + log.info("[I40] Shutdown mock http server"); + mockServer.stop(5); + } + + @LocalServerPort + private int localPort; + + @Test + void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { + webClient.get() + .uri("http://localhost:" + localPort + "/v1/customer/customer1") + .exchange() + .expectBody() + .consumeWith((result) -> { + String body = new String(result.getResponseBody()); + log.info("[I99] body={}", body); + assertEquals("/api/customer1", body); + }); + } + + @Test + void testWhenDslCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { + webClient.get() + .uri("http://localhost:" + localPort + "/v2/zip/123456") + .exchange() + .expectBody() + .consumeWith((result) -> { + String body = new String(result.getResponseBody()); + log.info("[I99] body={}", body); + assertTrue(body.matches("/api/zip/123456-\\d{3}")); + }); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java new file mode 100644 index 0000000000..a28eb68775 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java @@ -0,0 +1,64 @@ +package com.baeldung.springcloudgateway.webfilters; + +import org.junit.After; +import org.junit.Before; +import org.junit.jupiter.api.RepeatedTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +import redis.embedded.RedisServer; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("webfilters") +@TestConfiguration +public class RedisWebFilterFactoriesLiveTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(RedisWebFilterFactoriesLiveTest.class); + + private RedisServer redisServer; + + public RedisWebFilterFactoriesLiveTest() { + } + + @Before + public void postConstruct() { + this.redisServer = new RedisServer(6379); + redisServer.start(); + } + + @LocalServerPort + String port; + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + TestRestTemplate template; + + @RepeatedTest(25) + public void whenCallRedisGetThroughGateway_thenOKStatusOrIsReceived() { + String url = "http://localhost:" + port + "/redis/get"; + + ResponseEntity r = restTemplate.getForEntity(url, String.class); + // assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + LOGGER.info("Received: status->{}, reason->{}, remaining->{}", + r.getStatusCodeValue(), r.getStatusCode().getReasonPhrase(), + r.getHeaders().get("X-RateLimit-Remaining")); + } + + @After + public void preDestroy() { + redisServer.stop(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java new file mode 100644 index 0000000000..67e00a42fc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java @@ -0,0 +1,136 @@ +package com.baeldung.springcloudgateway.webfilters; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.assertj.core.api.Condition; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("webfilters") +public class WebFilterFactoriesLiveTest { + + @LocalServerPort + String port; + + @Autowired + private WebTestClient client; + + @Autowired + private TestRestTemplate restTemplate; + + @BeforeEach + public void configureClient() { + client = WebTestClient.bindToServer() + .baseUrl("http://localhost:" + port) + .build(); + } + + @Test + public void whenCallGetThroughGateway_thenAllHTTPRequestHeadersParametersAreSet() throws JSONException { + String url = "http://localhost:" + port + "/get"; + ResponseEntity response = restTemplate.getForEntity(url, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("My-Header-Good")).isEqualTo("Good"); + assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good"); + assertThat(headers.getString("My-Header-Set")).isEqualTo("Set"); + assertTrue(headers.isNull("My-Header-Remove")); + JSONObject vars = json.getJSONObject("args"); + assertThat(vars.getString("var")).isEqualTo("good"); + } + + @Test + public void whenCallHeaderPostThroughGateway_thenAllHTTPResponseHeadersAreSet() { + ResponseSpec response = client.post() + .uri("/header/post") + .exchange(); + + response.expectStatus() + .isOk() + .expectHeader() + .valueEquals("My-Header-Rewrite", "password=***") + .expectHeader() + .valueEquals("My-Header-Set", "Set") + .expectHeader() + .valueEquals("My-Header-Good", "Good") + .expectHeader() + .doesNotExist("My-Header-Remove"); + } + + @Test + public void whenCallPostThroughGateway_thenBodyIsRetrieved() throws JSONException { + String url = "http://localhost:" + port + "/post"; + + HttpEntity entity = new HttpEntity<>("content", new HttpHeaders()); + + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject data = json.getJSONObject("json"); + assertThat(data.getString("message")).isEqualTo("CONTENT"); + } + + @Test + public void whenCallPutThroughGateway_thenBodyIsRetrieved() throws JSONException { + String url = "http://localhost:" + port + "/put"; + + HttpEntity entity = new HttpEntity<>("CONTENT", new HttpHeaders()); + + ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + assertThat(json.getString("message")).isEqualTo("New Body"); + } + + @Test + public void whenCallDeleteThroughGateway_thenIsUnauthorizedCodeIsSet() { + ResponseSpec response = client.delete() + .uri("/delete") + .exchange(); + + response.expectStatus() + .isUnauthorized(); + } + + @Test + public void whenCallFakePostThroughGateway_thenIsUnauthorizedCodeIsSet() { + ResponseSpec response = client.post() + .uri("/fake/post") + .exchange(); + + response.expectStatus() + .is3xxRedirection(); + } + + @Test + public void whenCallStatus504ThroughGateway_thenCircuitBreakerIsExecuted() throws JSONException { + String url = "http://localhost:" + port + "/status/504"; + ResponseEntity response = restTemplate.getForEntity(url, String.class); + + JSONObject json = new JSONObject(response.getBody()); + assertThat(json.getString("url")).contains("anything"); + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json new file mode 100644 index 0000000000..ac920a271b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json @@ -0,0 +1,203 @@ +{ + "info": { + "_postman_id": "b3d00e23-c2cd-40ce-a90b-673efb25e5c0", + "name": "Baeldung - OAuth", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = pm.response.json();\r", + "pm.environment.set(\"access_token\", jsonData.access_token);\r", + "pm.environment.set(\"refresh_token\", jsonData.refresh_token);\r", + "pm.environment.set(\"backend_token\", \"Bearer \" + jsonData.access_token);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "client_id", + "value": "{{client_id}}", + "type": "text" + }, + { + "key": "client_secret", + "value": "{{client_secret}}", + "type": "text" + }, + { + "key": "grant_type", + "value": "password", + "type": "text" + }, + { + "key": "scope", + "value": "email roles profile", + "type": "text" + }, + { + "key": "username", + "value": "maxwell.smart", + "type": "text" + }, + { + "key": "password", + "value": "1234", + "type": "text" + } + ] + }, + "url": { + "raw": "{{keycloack_base}}/token", + "host": [ + "{{keycloack_base}}" + ], + "path": [ + "token" + ] + } + }, + "response": [] + }, + { + "name": "Quote", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8085/quotes/:symbol", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8085", + "path": [ + "quotes", + ":symbol" + ], + "variable": [ + { + "key": "symbol", + "value": "IBM" + } + ] + } + }, + "response": [] + }, + { + "name": "Quote via Gateway", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{access_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8086/quotes/:symbol", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8086", + "path": [ + "quotes", + ":symbol" + ], + "variable": [ + { + "key": "symbol", + "value": "IBM" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "keycloack_base", + "value": "http://localhost:8083/auth/realms/baeldung/protocol/openid-connect" + }, + { + "key": "client_id", + "value": "quotes-client" + }, + { + "key": "client_secret", + "value": "56be94c8-b20a-4374-899c-e39cb022d3f8" + } + ] +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..6980d119b1 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml index e7fe7e7485..f4d4073ef1 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml @@ -18,6 +18,7 @@ config discovery gateway + gateway-2 svc-book svc-rating customer-service From f1b3f233dc537d707dd491280648e5b57fb13178 Mon Sep 17 00:00:00 2001 From: Anastasios Ioannidis Date: Fri, 18 Aug 2023 11:30:56 +0300 Subject: [PATCH 002/135] JAVA-13321 Removed code unrelated to spring-cloud-gateway article topics --- .../gateway-2/README-OAuth.md | 40 ------------ .../spring-cloud-bootstrap/gateway-2/pom.xml | 44 ------------- .../oauth/backend/QuotesApplication.java | 44 ------------- .../oauth/backend/domain/Quote.java | 35 ---------- .../oauth/backend/web/QuoteApi.java | 34 ---------- .../ResourceServerGatewayApplication.java | 13 ---- .../KeycloakReactiveTokenInstrospector.java | 65 ------------------- .../resources/application-oauth-client.yml | 26 -------- .../resources/application-resource-server.yml | 19 ------ .../resources/quotes-application.properties | 12 ---- 10 files changed, 332 deletions(-) delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md deleted file mode 100644 index c186114589..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README-OAuth.md +++ /dev/null @@ -1,40 +0,0 @@ -# OAuth Test Setup - -In order to test the OAuth-secured gateway configurations, please follow the steps below - -## Keycloak setup - -1. Clone or download the https://github.com/Baeldung/spring-security-oauth project -2. Replace the file `oauth-rest/oauth-authorization-server/src/main/resources/baeldung-realm.json` - with the one provider here -3. Go to the oauth-rest/oauth-authorization-server folder and use maven to build the project -4. Run the Keycloack service with `mvn spring-boot:run` -5. Once Keycloak is up and running, go to `http://localhost:8083/auth/admin/master/console/#/realms/baeldung` and - log in with using `bael-admin/pass` as credentials -6. Create two test users, so that one belongs to the *Golden Customers* group and the other doesn't. - -## Quotes backend - -Use the provided maven profile: - -``` -$ mvn spring-boot:run -Pquotes-application -``` - -## Gateway as Resource Server - -Use the provided maven profile: - -``` -$ mvn spring-boot:run -Pgateway-as-resource-server -``` - -## Gateway as OAuth 2.0 Client - -Use the provided maven profile: - -``` -$ mvn spring-boot:run -Pgateway-as-oauth-client -``` - - diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml index dc42483dc5..520646cc7d 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -121,50 +121,6 @@ - - quotes-application - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.springcloudgateway.oauth.backend.QuotesApplication - - - - - - - gateway-as-resource-server - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.springcloudgateway.oauth.server.ResourceServerGatewayApplication - -Dspring.profiles.active=resource-server - - - - - - - gateway-as-oauth-client - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.springcloudgateway.oauth.server.ResourceServerGatewayApplication - -Dspring.profiles.active=oauth-client - - - - - gateway-url-rewrite diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java deleted file mode 100644 index 96daf8a73d..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/QuotesApplication.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - */ -package com.baeldung.springcloudgateway.oauth.backend; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.PropertySource; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector; -import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; - -import com.baeldung.springcloudgateway.oauth.shared.KeycloakReactiveTokenInstrospector; - -/** - * @author Philippe - * - */ -@SpringBootApplication -@PropertySource("classpath:quotes-application.properties") -@EnableWebFluxSecurity -public class QuotesApplication { - - public static void main(String[] args) { - SpringApplication.run(QuotesApplication.class); - } - - - @Bean - public ReactiveOpaqueTokenIntrospector keycloakIntrospector(OAuth2ResourceServerProperties props) { - - NimbusReactiveOpaqueTokenIntrospector delegate = new NimbusReactiveOpaqueTokenIntrospector( - props.getOpaquetoken().getIntrospectionUri(), - props.getOpaquetoken().getClientId(), - props.getOpaquetoken().getClientSecret()); - - return new KeycloakReactiveTokenInstrospector(delegate); - } - - -} - diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java deleted file mode 100644 index 042cfa63fa..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/domain/Quote.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.springcloudgateway.oauth.backend.domain; - - -public class Quote { - - private String symbol; - private double price; - - /** - * @return the symbol - */ - public String getSymbol() { - return symbol; - } - /** - * @param symbol the symbol to set - */ - public void setSymbol(String symbol) { - this.symbol = symbol; - } - /** - * @return the price - */ - public double getPrice() { - return price; - } - /** - * @param price the price to set - */ - public void setPrice(double price) { - this.price = price; - } - - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java deleted file mode 100644 index 6d3721166c..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/backend/web/QuoteApi.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.baeldung.springcloudgateway.oauth.backend.web; - -import javax.annotation.PostConstruct; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.springcloudgateway.oauth.backend.domain.Quote; - -import reactor.core.publisher.Mono; - -@RestController -public class QuoteApi { - private static final GrantedAuthority GOLD_CUSTOMER = new SimpleGrantedAuthority("gold"); - - @GetMapping("/quotes/{symbol}") - public Mono getQuote(@PathVariable("symbol") String symbol, BearerTokenAuthentication auth ) { - - Quote q = new Quote(); - q.setSymbol(symbol); - - if ( auth.getAuthorities().contains(GOLD_CUSTOMER)) { - q.setPrice(10.0); - } - else { - q.setPrice(12.0); - } - return Mono.just(q); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java deleted file mode 100644 index 1b85867f3b..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/server/ResourceServerGatewayApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.baeldung.springcloudgateway.oauth.server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; - -@SpringBootApplication -@EnableWebFluxSecurity -public class ResourceServerGatewayApplication { - public static void main(String[] args) { - SpringApplication.run(ResourceServerGatewayApplication.class,args); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java deleted file mode 100644 index e834e6934d..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/oauth/shared/KeycloakReactiveTokenInstrospector.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * - */ -package com.baeldung.springcloudgateway.oauth.shared; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; - -import reactor.core.publisher.Mono; - -/** - * Custom ReactiveTokenIntrospector to map realm roles into Spring GrantedAuthorities - * - */ -public class KeycloakReactiveTokenInstrospector implements ReactiveOpaqueTokenIntrospector { - - private final ReactiveOpaqueTokenIntrospector delegate; - - public KeycloakReactiveTokenInstrospector(ReactiveOpaqueTokenIntrospector delegate) { - this.delegate = delegate; - } - - @Override - public Mono introspect(String token) { - - return delegate.introspect(token) - .map( this::mapPrincipal); - } - - protected OAuth2AuthenticatedPrincipal mapPrincipal(OAuth2AuthenticatedPrincipal principal) { - - return new DefaultOAuth2AuthenticatedPrincipal( - principal.getName(), - principal.getAttributes(), - extractAuthorities(principal)); - } - - protected Collection extractAuthorities(OAuth2AuthenticatedPrincipal principal) { - - // - Map> realm_access = principal.getAttribute("realm_access"); - List roles = realm_access.getOrDefault("roles", Collections.emptyList()); - List rolesAuthorities = roles.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - Set allAuthorities = new HashSet<>(); - allAuthorities.addAll(principal.getAuthorities()); - allAuthorities.addAll(rolesAuthorities); - - return allAuthorities; - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml deleted file mode 100644 index b097c54eb1..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-oauth-client.yml +++ /dev/null @@ -1,26 +0,0 @@ -server: - port: 8087 -spring: - cloud: - gateway: - redis: - enabled: false - routes: - - id: quotes - uri: http://localhost:8085 - predicates: - - Path=/quotes/** - filters: - TokenRelay= - security: - oauth2: - client: provider: keycloak: - issuer-uri: http://localhost:8083/auth/realms/baeldung - registration: quotes-client: - provider: keycloak - client-id: quotes-client - client-secret: 0e082231-a70d-48e8-b8a5-fbfb743041b6 - scope: - email - - profile - - roles - - \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml deleted file mode 100644 index 14f713a04a..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-resource-server.yml +++ /dev/null @@ -1,19 +0,0 @@ -server: - port: 8086 -spring: - security: - oauth2: - resourceserver: - opaquetoken: - introspection-uri: http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/token/introspect - client-id: quotes-client - client-secret: 0e082231-a70d-48e8-b8a5-fbfb743041b6 - cloud: - gateway: - redis: - enabled: false - routes: - - id: quotes - uri: http://localhost:8085 - predicates: - - Path=/quotes/** diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties deleted file mode 100644 index 48e8999b1b..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/quotes-application.properties +++ /dev/null @@ -1,12 +0,0 @@ -server.port=8085 -# Disable gateway & redis as we don't need them in this application -spring.cloud.gateway.enabled=false -spring.cloud.gateway.redis.enabled=false - -# Resource server settings -spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/token/introspect -spring.security.oauth2.resourceserver.opaquetoken.client-id=quotes-client -spring.security.oauth2.resourceserver.opaquetoken.client-secret=0e082231-a70d-48e8-b8a5-fbfb743041b6 - - - From fa34902b702d98b542bd30207e9b11479d5af23e Mon Sep 17 00:00:00 2001 From: mcasari Date: Sat, 19 Aug 2023 23:42:04 +0200 Subject: [PATCH 003/135] shallow vs deep copy first commit --- shallow-deep-copy/README.md | 7 +++++ shallow-deep-copy/pom.xml | 16 ++++++++++ .../baeldung/shallowdeepcopy/Dependency.java | 23 ++++++++++++++ .../com/baeldung/shallowdeepcopy/Main.java | 31 +++++++++++++++++++ .../src/main/resources/logback.xml | 13 ++++++++ .../ShallowDeepCopyUnitTest.java | 27 ++++++++++++++++ 6 files changed, 117 insertions(+) create mode 100644 shallow-deep-copy/README.md create mode 100644 shallow-deep-copy/pom.xml create mode 100644 shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java create mode 100644 shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java create mode 100644 shallow-deep-copy/src/main/resources/logback.xml create mode 100644 shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java diff --git a/shallow-deep-copy/README.md b/shallow-deep-copy/README.md new file mode 100644 index 0000000000..e1a426a138 --- /dev/null +++ b/shallow-deep-copy/README.md @@ -0,0 +1,7 @@ +## Shallow vs Deep Copy + +This module contains an article about shallow vs deep copy of Java objects + +### Relevant articles: + +- [Creating a deep vs shallow copy of an object in Java](https://drafts.baeldung.com/?p=172294&preview=true) diff --git a/shallow-deep-copy/pom.xml b/shallow-deep-copy/pom.xml new file mode 100644 index 0000000000..01c1430f28 --- /dev/null +++ b/shallow-deep-copy/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + shallow-deep-copy + shallow-deep-copy + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + \ No newline at end of file diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java new file mode 100644 index 0000000000..a5da5fc163 --- /dev/null +++ b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java @@ -0,0 +1,23 @@ +package com.baeldung.shallowdeepcopy; + +public class Dependency implements Cloneable { + private int value = 13; + + public Dependency(int value) { + super(); + this.value = value; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java new file mode 100644 index 0000000000..fb24007162 --- /dev/null +++ b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java @@ -0,0 +1,31 @@ +package com.baeldung.shallowdeepcopy; + +public class Main implements Cloneable { + private Dependency dependency; + + public Main(Dependency dependency) { + super(); + this.dependency = dependency; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + public Object deepClone() throws CloneNotSupportedException { + Main dependentClone = (Main) super.clone(); + Dependency dependencyClone = (Dependency) this.dependency.clone(); + dependentClone.setDependency(dependencyClone); + return dependentClone; + } + + public Dependency getDependency() { + return dependency; + } + + public void setDependency(Dependency dependency) { + this.dependency = dependency; + } + +} diff --git a/shallow-deep-copy/src/main/resources/logback.xml b/shallow-deep-copy/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/shallow-deep-copy/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java b/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java new file mode 100644 index 0000000000..321c2df327 --- /dev/null +++ b/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.shallowdeepcopy; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class ShallowDeepCopyUnitTest { + + @Test + public void givenAnObjectAndADependency_whenShallowClonedAndDepencyChanges_ThenDepencyHasNewValue() throws Exception { + Dependency dependency = new Dependency(13); + Main main = new Main(dependency); + Main shallowClone = (Main) main.clone(); + dependency.setValue(17); + assertEquals(17, shallowClone.getDependency().getValue()); + } + + + @Test + public void givenAnObjectAndADependency_whenDeepClonedAndDepencyChanges_ThenDepencyKeepsOldValue() throws Exception { + Dependency dependency = new Dependency(13); + Main main = new Main(dependency); + Main deepClone = (Main) main.deepClone(); + dependency.setValue(17); + assertEquals(13, deepClone.getDependency().getValue()); + } +} From 8a6e3f233ec0591fe20d82fcf00c80cb8164b577 Mon Sep 17 00:00:00 2001 From: mcasari Date: Tue, 22 Aug 2023 19:49:54 +0200 Subject: [PATCH 004/135] Format content with baeldung formatter --- shallow-deep-copy/pom.xml | 22 ++++----- .../baeldung/shallowdeepcopy/Dependency.java | 32 ++++++------- .../com/baeldung/shallowdeepcopy/Main.java | 48 +++++++++---------- .../src/main/resources/logback.xml | 19 ++++---- .../ShallowDeepCopyUnitTest.java | 37 +++++++------- 5 files changed, 80 insertions(+), 78 deletions(-) diff --git a/shallow-deep-copy/pom.xml b/shallow-deep-copy/pom.xml index 01c1430f28..323f720df3 100644 --- a/shallow-deep-copy/pom.xml +++ b/shallow-deep-copy/pom.xml @@ -1,16 +1,16 @@ - 4.0.0 - shallow-deep-copy - shallow-deep-copy - jar + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + shallow-deep-copy + shallow-deep-copy + jar - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + \ No newline at end of file diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java index a5da5fc163..2550acd268 100644 --- a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java +++ b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java @@ -1,23 +1,23 @@ package com.baeldung.shallowdeepcopy; public class Dependency implements Cloneable { - private int value = 13; - - public Dependency(int value) { - super(); - this.value = value; - } + private int value = 13; - public int getValue() { - return value; - } + public Dependency(int value) { + super(); + this.value = value; + } - public void setValue(int value) { - this.value = value; - } + public int getValue() { + return value; + } - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } + public void setValue(int value) { + this.value = value; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); + } } diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java index fb24007162..33d565bb10 100644 --- a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java +++ b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java @@ -1,31 +1,31 @@ package com.baeldung.shallowdeepcopy; public class Main implements Cloneable { - private Dependency dependency; - - public Main(Dependency dependency) { - super(); - this.dependency = dependency; - } + private Dependency dependency; - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } + public Main(Dependency dependency) { + super(); + this.dependency = dependency; + } - public Object deepClone() throws CloneNotSupportedException { - Main dependentClone = (Main) super.clone(); - Dependency dependencyClone = (Dependency) this.dependency.clone(); - dependentClone.setDependency(dependencyClone); - return dependentClone; - } - - public Dependency getDependency() { - return dependency; - } + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + public Object deepClone() throws CloneNotSupportedException { + Main dependentClone = (Main) super.clone(); + Dependency dependencyClone = (Dependency) this.dependency.clone(); + dependentClone.setDependency(dependencyClone); + return dependentClone; + } + + public Dependency getDependency() { + return dependency; + } + + public void setDependency(Dependency dependency) { + this.dependency = dependency; + } - public void setDependency(Dependency dependency) { - this.dependency = dependency; - } - } diff --git a/shallow-deep-copy/src/main/resources/logback.xml b/shallow-deep-copy/src/main/resources/logback.xml index 7d900d8ea8..830ab22727 100644 --- a/shallow-deep-copy/src/main/resources/logback.xml +++ b/shallow-deep-copy/src/main/resources/logback.xml @@ -1,13 +1,14 @@ - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + - - - + + + \ No newline at end of file diff --git a/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java b/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java index 321c2df327..f75bbc040b 100644 --- a/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java +++ b/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java @@ -5,23 +5,24 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; class ShallowDeepCopyUnitTest { - - @Test - public void givenAnObjectAndADependency_whenShallowClonedAndDepencyChanges_ThenDepencyHasNewValue() throws Exception { - Dependency dependency = new Dependency(13); - Main main = new Main(dependency); - Main shallowClone = (Main) main.clone(); - dependency.setValue(17); - assertEquals(17, shallowClone.getDependency().getValue()); - } - - @Test - public void givenAnObjectAndADependency_whenDeepClonedAndDepencyChanges_ThenDepencyKeepsOldValue() throws Exception { - Dependency dependency = new Dependency(13); - Main main = new Main(dependency); - Main deepClone = (Main) main.deepClone(); - dependency.setValue(17); - assertEquals(13, deepClone.getDependency().getValue()); - } + @Test + public void givenAnObjectAndADependency_whenShallowClonedAndDepencyChanges_ThenDepencyHasNewValue() throws Exception { + Dependency dependency = new Dependency(13); + Main main = new Main(dependency); + Main shallowClone = (Main) main.clone(); + dependency.setValue(17); + assertEquals(17, shallowClone.getDependency() + .getValue()); + } + + @Test + public void givenAnObjectAndADependency_whenDeepClonedAndDepencyChanges_ThenDepencyKeepsOldValue() throws Exception { + Dependency dependency = new Dependency(13); + Main main = new Main(dependency); + Main deepClone = (Main) main.deepClone(); + dependency.setValue(17); + assertEquals(13, deepClone.getDependency() + .getValue()); + } } From d20c1616c15bc65f73d574630f4f1f7323270eec Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Sat, 2 Sep 2023 12:21:01 -0600 Subject: [PATCH 005/135] Add form examples to Jersey modules --- jersey/pom.xml | 7 ++- .../server/form/FormExampleResource.java | 61 +++++++++++++++++++ .../main/resources/formexamples/example1.html | 16 +++++ .../main/resources/formexamples/example2.html | 18 ++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java create mode 100644 jersey/src/main/resources/formexamples/example1.html create mode 100644 jersey/src/main/resources/formexamples/example2.html diff --git a/jersey/pom.xml b/jersey/pom.xml index 005fa85077..d019d31e1e 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -76,6 +76,11 @@ jersey-apache-connector ${jersey.version} + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey.version} + @@ -103,4 +108,4 @@ 3.3.2 - \ No newline at end of file + diff --git a/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java new file mode 100644 index 0000000000..15e82679ef --- /dev/null +++ b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java @@ -0,0 +1,61 @@ +package com.baeldung.jersey.server.form; + +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +@Path("form") +public class FormExampleResource +{ + @GET + @Path("/example1") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample1() throws Exception + { + File f = new File("src/main/resources/html/example1.html"); + return new FileInputStream(f); + } + + @GET + @Path("/example2") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample2() throws Exception + { + File f = new File("src/main/resources/html/example2.html"); + return new FileInputStream(f); + } + + @POST + @Path("/example1") + public String example1(@FormParam("first_name") String firstName, + @FormParam("last_name") String lastName, + @FormParam("age") String age) + { + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age; + } + + @POST + @Path("/example2") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String example2(@FormDataParam("first_name") String firstName, + @FormDataParam("last_name") String lastName, + @FormDataParam("age") String age, + @FormDataParam("photo") InputStream photo) + throws Exception + { + int len; + int size = 1024; + byte[] buf; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + buf = new byte[size]; + while ((len = photo.read(buf, 0, size)) != -1) + bos.write(buf, 0, len); + buf = bos.toByteArray(); + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age + ", Photo (# of bytes) = " + buf.length; + } +} diff --git a/jersey/src/main/resources/formexamples/example1.html b/jersey/src/main/resources/formexamples/example1.html new file mode 100644 index 0000000000..6335dcce08 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example1.html @@ -0,0 +1,16 @@ + + + Example 1 using @FormParam + + +
+ + + + + + + +
+ + diff --git a/jersey/src/main/resources/formexamples/example2.html b/jersey/src/main/resources/formexamples/example2.html new file mode 100644 index 0000000000..4875c652a4 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example2.html @@ -0,0 +1,18 @@ + + + Example 2 using @FormDataParam + + +
+ + + + + + + + + +
+ + From 4e77570581c66ef1e428756f509ad690cbf5db5d Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Sun, 3 Sep 2023 14:45:27 +0200 Subject: [PATCH 006/135] BAEL-6923: added comments about docker env --- .../com/baeldung/testcontainers/DynamicPropertiesLiveTest.java | 2 ++ .../java/com/baeldung/testcontainers/LocalDevApplication.java | 3 +++ .../com/baeldung/testcontainers/ServiceConnectionLiveTest.java | 2 ++ 3 files changed, 7 insertions(+) diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java index e8818c1019..2633f227d4 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java @@ -25,6 +25,8 @@ import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; @Testcontainers @SpringBootTest(webEnvironment = DEFINED_PORT) @DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment class DynamicPropertiesLiveTest { @Container static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java index a94c0f772a..1b6fe32c97 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java @@ -8,6 +8,9 @@ import org.springframework.context.annotation.Bean; import org.testcontainers.containers.MongoDBContainer; import org.testcontainers.utility.DockerImageName; + +// Testcontainers require a valid docker installation. +// When running the app locally, ensure you have a valid Docker environment class LocalDevApplication { public static void main(String[] args) { diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java index 838ee127f6..51b69c44b3 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java @@ -24,6 +24,8 @@ import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; @Testcontainers @SpringBootTest(webEnvironment = DEFINED_PORT) @DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment class ServiceConnectionLiveTest { @Container From 982401a329a86e1a124bfc6d451ac1b31069d458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 28 Jul 2023 19:15:07 +0200 Subject: [PATCH 007/135] [BAEL-6529] Update Springwolf version to 0.13.0 Co-authored-by: Timon Back --- .../src/test/resources/asyncapi.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json index 0198733c1c..45be27f571 100644 --- a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json +++ b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json @@ -18,7 +18,9 @@ "operationId": "incoming-topic_publish", "description": "More details for the incoming topic", "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } }, "message": { "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", @@ -32,7 +34,9 @@ "$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto" }, "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } } } } @@ -42,7 +46,9 @@ "operationId": "outgoing-topic_subscribe", "description": "More details for the outgoing topic", "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } }, "message": { "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", @@ -56,7 +62,9 @@ "$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto" }, "bindings": { - "kafka": { } + "kafka": { + "bindingVersion": "0.4.0" + } } } } From c7d0b46531dd52afac7782830ad8262a1a1abd50 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Mon, 4 Sep 2023 22:02:38 +0200 Subject: [PATCH 008/135] [BAEL-6529] Update Springwolf version to 0.14.0 --- spring-boot-modules/spring-boot-documentation/pom.xml | 4 ++-- .../src/test/resources/asyncapi.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-modules/spring-boot-documentation/pom.xml b/spring-boot-modules/spring-boot-documentation/pom.xml index f0806b3c75..3ac2799258 100644 --- a/spring-boot-modules/spring-boot-documentation/pom.xml +++ b/spring-boot-modules/spring-boot-documentation/pom.xml @@ -93,8 +93,8 @@ 2.2.11 - 0.12.1 - 0.8.0 + 0.14.0 + 0.14.0 1.18.3 diff --git a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json index 45be27f571..260f9382f9 100644 --- a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json +++ b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json @@ -8,7 +8,7 @@ "defaultContentType": "application/json", "servers": { "kafka": { - "url": "localhost:9092", + "url": "localhost:29092", "protocol": "kafka" } }, From 68b78c845ce06efc2de53239c4bd76e06f7d93a8 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Tue, 5 Sep 2023 08:16:27 +0200 Subject: [PATCH 009/135] Update asyncapi.json --- .../spring-boot-documentation/src/test/resources/asyncapi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json index 260f9382f9..45be27f571 100644 --- a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json +++ b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json @@ -8,7 +8,7 @@ "defaultContentType": "application/json", "servers": { "kafka": { - "url": "localhost:29092", + "url": "localhost:9092", "protocol": "kafka" } }, From 6929fe146925d4e9dafba8e25448739a2c7bd367 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 15 Sep 2023 00:04:31 +0530 Subject: [PATCH 010/135] BAEL-6963 BAEL-6963 Changes --- .../multiple/objecttypes/CustomObject.java | 13 ++++++++ .../MultipleObjectTypeArrayList.java | 32 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java create mode 100644 core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java new file mode 100644 index 0000000000..ae30f2bc1c --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java @@ -0,0 +1,13 @@ +package com.baeldung.list.multiple.objecttypes; + +public class CustomObject { + String classData; + + CustomObject(String classData) { + this.classData = classData; + } + + public String getClassData() { + return this.classData; + } +} diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java new file mode 100644 index 0000000000..7ce99b7b9d --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java @@ -0,0 +1,32 @@ +package com.baeldung.list.multiple.objecttypes; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MultipleObjectTypeArrayList { + + public static void main(String[] args) { + + List multiTypeList = new ArrayList<>(); + multiTypeList.add(Integer.valueOf(10)); + multiTypeList.add(Double.valueOf(11.5)); + multiTypeList.add("String Data"); + multiTypeList.add(Arrays.asList(1, 2, 3)); + multiTypeList.add(new CustomObject("Class Data")); + + for (Object dataObj : multiTypeList) { + if (dataObj instanceof Integer intData) + System.out.println(intData); + if (dataObj instanceof Double doubleData) + System.out.println(doubleData); + if (dataObj instanceof String stringData) + System.out.println(stringData); + if (dataObj instanceof List intList) + System.out.println(intList); + if (dataObj instanceof CustomObject customObj) + System.out.println(customObj.getClassData()); + } + } + +} From b7b167ea1ea0938943919ad1115e56d2f48e395b Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 15 Sep 2023 18:39:05 +0530 Subject: [PATCH 011/135] Updated output --- .../objecttypes/MultipleObjectTypeArrayList.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java index 7ce99b7b9d..33537a797f 100644 --- a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java @@ -17,15 +17,15 @@ public class MultipleObjectTypeArrayList { for (Object dataObj : multiTypeList) { if (dataObj instanceof Integer intData) - System.out.println(intData); + System.out.println("Integer Data : " + intData); if (dataObj instanceof Double doubleData) - System.out.println(doubleData); + System.out.println("Double Data : " + doubleData); if (dataObj instanceof String stringData) - System.out.println(stringData); + System.out.println("String Data : " + stringData); if (dataObj instanceof List intList) - System.out.println(intList); + System.out.println("List Data : " + intList); if (dataObj instanceof CustomObject customObj) - System.out.println(customObj.getClassData()); + System.out.println("CustomObject Data : " + customObj.getClassData()); } } From 5159e8ab6705908ce1509e47e7caad5422fe2623 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 15 Sep 2023 19:48:05 +0530 Subject: [PATCH 012/135] Program Updates --- .../multiple/objecttypes/MultipleObjectTypeArrayList.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java index 33537a797f..12acc3843b 100644 --- a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java @@ -7,8 +7,9 @@ import java.util.List; public class MultipleObjectTypeArrayList { public static void main(String[] args) { - - List multiTypeList = new ArrayList<>(); + + ArrayList multiTypeList = new ArrayList<>(); + multiTypeList.add(Integer.valueOf(10)); multiTypeList.add(Double.valueOf(11.5)); multiTypeList.add("String Data"); From 829593380b9ee3c19d248396c2668e70e29a9bf5 Mon Sep 17 00:00:00 2001 From: panos-kakos Date: Mon, 18 Sep 2023 12:34:20 +0300 Subject: [PATCH 013/135] [JAVA-22209] Upgraded spring-cloud-zuul-eureka-integration module to jdk17 + fixed tests in spring-cloud-archaius module --- pom.xml | 4 +++- spring-cloud-modules/pom.xml | 2 +- .../spring-cloud-archaius/pom.xml | 4 +++- .../pom.xml | 3 ++- .../pom.xml | 16 ++++++++++++++++ .../spring-cloud-archaius-jdbc-config/pom.xml | 9 +++++++++ .../spring-cloud-stream-starters/pom.xml | 3 +-- .../eureka-client/pom.xml | 18 ++++++++++++++++++ .../eureka-server/pom.xml | 18 ++++++++++++++++++ .../zuul-server/pom.xml | 18 ++++++++++++++++++ 10 files changed, 89 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c65f6ce62d..86d7d3328c 100644 --- a/pom.xml +++ b/pom.xml @@ -726,6 +726,7 @@ spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline spring-core @@ -999,6 +1000,8 @@ spring-drools spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-contract + spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline spring-core @@ -1210,7 +1213,6 @@ gradle-modules/gradle/maven-to-gradle persistence-modules/spring-data-neo4j spring-actuator - spring-cloud-modules/spring-cloud-contract diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 9c926bbe61..73276d7e0f 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -31,7 +31,7 @@ spring-cloud-connectors-heroku spring-cloud-aws spring-cloud-consul - spring-cloud-zuul-eureka-integration + spring-cloud-kubernetes spring-cloud-open-service-broker diff --git a/spring-cloud-modules/spring-cloud-archaius/pom.xml b/spring-cloud-modules/spring-cloud-archaius/pom.xml index 4d7ca3943d..3e90c7390c 100644 --- a/spring-cloud-modules/spring-cloud-archaius/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/pom.xml @@ -40,6 +40,7 @@ org.springframework.cloud spring-cloud-starter-netflix-archaius + ${spring-cloud-starter-netflix-archaius.version} org.springframework.boot @@ -54,7 +55,8 @@ - 2.0.3.RELEASE + 2.2.10.RELEASE + 2.2.10.RELEASE \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml index 6e25ace6a8..600fedc774 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml @@ -36,7 +36,7 @@ org.projectlombok lombok - provided + ${lombok.version} @@ -44,6 +44,7 @@ 1.11.407 5.0.3 0.7.6 + 1.18.26 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml index f90570abc2..383ad6a780 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml @@ -37,6 +37,22 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + + + + + + 2.0.1.RELEASE diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml index 7fb5747739..2871f129b5 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml @@ -27,6 +27,15 @@ h2 runtime + + org.projectlombok + lombok + ${lombok.version} + + + 1.18.26 + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml index eee5b27396..95176d1e5c 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml @@ -3,7 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung.spring.cloud spring-cloud-stream-starters 1.0.0-SNAPSHOT spring-cloud-stream-starters @@ -32,7 +31,7 @@ - 2021.0.0 + 2022.0.4 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml index 3960cfde5d..46b3e7047f 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml index c9bc120e4d..796b908bca 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml index 76d899447f..11cc992523 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml @@ -61,6 +61,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 From da0beaeee0af95bec423a6979169e523ead13e4a Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Tue, 19 Sep 2023 21:25:59 +0530 Subject: [PATCH 014/135] Restructuring to new module Restructuring to new module --- .../README.md | 6 +++ .../pom.xml | 38 +++++++++++++++++++ .../multiple/objecttypes/CustomObject.java | 0 .../MultipleObjectTypeArrayList.java | 21 ++++++---- core-java-modules/pom.xml | 1 + 5 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 core-java-modules/core-java-collections-array-list-2/README.md create mode 100644 core-java-modules/core-java-collections-array-list-2/pom.xml rename core-java-modules/{core-java-collections-array-list => core-java-collections-array-list-2}/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java (100%) rename core-java-modules/{core-java-collections-array-list => core-java-collections-array-list-2}/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java (59%) diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md new file mode 100644 index 0000000000..feef70a6dc --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -0,0 +1,6 @@ +## Core Java Collections ArrayList + +This module contains articles about the Java ArrayList collection + +### Relevant Articles: +- [Create an ArrayList with Multiple Object Types](https://drafts.baeldung.com/create-an-arraylist-with-multiple-object-types/) \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml new file mode 100644 index 0000000000..b0622368ad --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -0,0 +1,38 @@ + + 4.0.0 + core-java-collections-array-list-2 + core-java-collections-array-list-2 + jar + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + + 16 + 16 + 3.0.0-M3 + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java similarity index 100% rename from core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java similarity index 59% rename from core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java index 12acc3843b..34610785cb 100644 --- a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java @@ -1,5 +1,7 @@ package com.baeldung.list.multiple.objecttypes; +import java.math.BigInteger; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -7,27 +9,32 @@ import java.util.List; public class MultipleObjectTypeArrayList { public static void main(String[] args) { - + ArrayList multiTypeList = new ArrayList<>(); - + multiTypeList.add(Integer.valueOf(10)); multiTypeList.add(Double.valueOf(11.5)); multiTypeList.add("String Data"); multiTypeList.add(Arrays.asList(1, 2, 3)); multiTypeList.add(new CustomObject("Class Data")); + multiTypeList.add(BigInteger.valueOf(123456789)); + multiTypeList.add(LocalDate.of(2023, 9, 19)); for (Object dataObj : multiTypeList) { if (dataObj instanceof Integer intData) System.out.println("Integer Data : " + intData); - if (dataObj instanceof Double doubleData) + else if (dataObj instanceof Double doubleData) System.out.println("Double Data : " + doubleData); - if (dataObj instanceof String stringData) + else if (dataObj instanceof String stringData) System.out.println("String Data : " + stringData); - if (dataObj instanceof List intList) + else if (dataObj instanceof List intList) System.out.println("List Data : " + intList); - if (dataObj instanceof CustomObject customObj) + else if (dataObj instanceof CustomObject customObj) System.out.println("CustomObject Data : " + customObj.getClassData()); + else if (dataObj instanceof BigInteger bigIntData) + System.out.println("BigInteger Data : " + bigIntData); + else if (dataObj instanceof LocalDate localDate) + System.out.println("LocalDate Data : " + localDate.toString()); } } - } diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index e9285eaf1e..88797a1bf3 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -177,6 +177,7 @@ core-java-collections-maps-6 core-java-records core-java-9-jigsaw + core-java-collections-array-list-2 From 50515d3070194f66ad493a7b560b89f50bafb6ca Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Tue, 19 Sep 2023 23:39:38 +0530 Subject: [PATCH 015/135] Additional Approach Changes --- .../AlternativeMultipeTypeList.java | 46 +++++++++++++++++++ .../multiple/objecttypes/CustomObject.java | 10 ++++ .../objecttypes/UserFunctionalInterface.java | 18 ++++++++ 3 files changed, 74 insertions(+) create mode 100644 core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java create mode 100644 core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java new file mode 100644 index 0000000000..ddef57e41c --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java @@ -0,0 +1,46 @@ +package com.baeldung.list.multiple.objecttypes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Predicate; + +public class AlternativeMultipeTypeList { + + public static void main(String[] args) { + // List of Numbers + ArrayList myList = new ArrayList<>(); + myList.add(1.2); + myList.add(2); + myList.add(-3.5); + + // List of Map + ArrayList diffMapList = new ArrayList<>(); + diffMapList.add(new HashMap<>()); + diffMapList.add(new TreeMap<>()); + diffMapList.add(new LinkedHashMap<>()); + + ArrayList objList = new ArrayList<>(); + objList.add(new CustomObject("obj1", 1)); + objList.add(new CustomObject("obj2", 2)); + + List dataList = new ArrayList<>(); + + Predicate myPricate = inputData -> (inputData instanceof String || inputData instanceof Integer); + + UserFunctionalInterface myInterface = (listObj, data) -> { + if (myPricate.test(data)) + listObj.add(data); + return listObj; + }; + + myInterface.addToList(dataList, Integer.valueOf(2)); + myInterface.addToList(dataList, Double.valueOf(3.33)); + myInterface.addToList(dataList, "String Value"); + myInterface.printList(dataList); + } + +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java index ae30f2bc1c..f4d4be989d 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java @@ -2,12 +2,22 @@ package com.baeldung.list.multiple.objecttypes; public class CustomObject { String classData; + Integer intData; CustomObject(String classData) { this.classData = classData; } + CustomObject(String classData, Integer intData) { + this.classData = classData; + this.intData = intData; + } + public String getClassData() { return this.classData; } + + public Integer getIntData() { + return this.intData; + } } diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java new file mode 100644 index 0000000000..7e39d5a152 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java @@ -0,0 +1,18 @@ +package com.baeldung.list.multiple.objecttypes; + +import java.util.List; + +@FunctionalInterface +public interface UserFunctionalInterface { + + List addToList(List list, Object data); + + default void printList(List dataList) { + for (Object data : dataList) { + if (data instanceof String stringData) + System.out.println("String Data: " + stringData); + if (data instanceof Integer intData) + System.out.println("Integer Data: " + intData); + } + } +} From 0f425a457365e2829a289142c3dd31f2e8e8954b Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Tue, 19 Sep 2023 23:45:25 +0530 Subject: [PATCH 016/135] Updated comments --- .../multiple/objecttypes/AlternativeMultipeTypeList.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java index ddef57e41c..d80f4627d3 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java @@ -11,22 +11,24 @@ import java.util.function.Predicate; public class AlternativeMultipeTypeList { public static void main(String[] args) { - // List of Numbers + // List of Parent Class ArrayList myList = new ArrayList<>(); myList.add(1.2); myList.add(2); myList.add(-3.5); - // List of Map + // List of Interface type ArrayList diffMapList = new ArrayList<>(); diffMapList.add(new HashMap<>()); diffMapList.add(new TreeMap<>()); diffMapList.add(new LinkedHashMap<>()); + // List of Custom Object ArrayList objList = new ArrayList<>(); objList.add(new CustomObject("obj1", 1)); objList.add(new CustomObject("obj2", 2)); + // List via Functional Interface List dataList = new ArrayList<>(); Predicate myPricate = inputData -> (inputData instanceof String || inputData instanceof Integer); From 4ce8b0e70a341783254dcbb718841742f4b47409 Mon Sep 17 00:00:00 2001 From: mcasari Date: Tue, 19 Sep 2023 21:53:05 +0200 Subject: [PATCH 017/135] Test cases for float to BigDecimal conversion - first commit --- convert-float-to-bigdecimal/README.md | 7 +++ convert-float-to-bigdecimal/pom.xml | 16 +++++++ .../src/main/resources/logback.xml | 14 ++++++ .../ConvertFloatToBigDecimalUnitTest.java | 48 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 convert-float-to-bigdecimal/README.md create mode 100644 convert-float-to-bigdecimal/pom.xml create mode 100644 convert-float-to-bigdecimal/src/main/resources/logback.xml create mode 100644 convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java diff --git a/convert-float-to-bigdecimal/README.md b/convert-float-to-bigdecimal/README.md new file mode 100644 index 0000000000..e01c981831 --- /dev/null +++ b/convert-float-to-bigdecimal/README.md @@ -0,0 +1,7 @@ +## Shallow vs Deep Copy + +This module contains an article about converting float to BigDecimal in Java + +### Relevant articles: + +- [Converting from Float to BigDecimal in Java](https://drafts.baeldung.com/?p=175240&preview=true) diff --git a/convert-float-to-bigdecimal/pom.xml b/convert-float-to-bigdecimal/pom.xml new file mode 100644 index 0000000000..8fa20b300f --- /dev/null +++ b/convert-float-to-bigdecimal/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + convert-float-to-bigdecimal + convert-float-to-bigdecimal + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + \ No newline at end of file diff --git a/convert-float-to-bigdecimal/src/main/resources/logback.xml b/convert-float-to-bigdecimal/src/main/resources/logback.xml new file mode 100644 index 0000000000..830ab22727 --- /dev/null +++ b/convert-float-to-bigdecimal/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java b/convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java new file mode 100644 index 0000000000..c43d2ab87a --- /dev/null +++ b/convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.convertfloattobigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +class ConvertFloatToBigDecimalUnitTest { + + @Test + public void whenFloatComparedWithDifferentValues_thenCouldMatch() { + assertNotEquals(1.1f, 1.09f); + assertEquals(1.1f, 1.09999999f); + } + + @Test + public void whenCreatedFromFloat_thenCouldNotMatch() { + float floatToConvert = 0.5f; + BigDecimal bdFromFloat = new BigDecimal(floatToConvert); + assertEquals("0.5", bdFromFloat.toString()); + floatToConvert = 1.1f; + bdFromFloat = new BigDecimal(floatToConvert); + assertNotEquals("1.1", bdFromFloat.toString()); + } + + @Test + public void whenCreatedFromString_thenMatches() { + String floatValue = Float.toString(1.1f); + BigDecimal bdFromString = new BigDecimal(floatValue); + assertEquals("1.1", bdFromString.toString()); + } + + @Test + public void whenCreatedByValueOfAndIsFloat_thenDoesNotMatch() { + float floatToConvert = 1.1f; + BigDecimal bdByValueOf = BigDecimal.valueOf(floatToConvert); + assertNotEquals("1.1", bdByValueOf.toString()); + } + + @Test + public void whenCreatedByValueOfAndIsDouble_thenMatches() { + double doubleToConvert = 1.1d; + BigDecimal bdByValueOf = BigDecimal.valueOf(doubleToConvert); + assertEquals("1.1", bdByValueOf.toString()); + } +} From e8c2e2cb9637daf75ec06660ec1999c332cb7c35 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Wed, 20 Sep 2023 17:34:27 +0330 Subject: [PATCH 018/135] #BAEL-6916: remove xml context --- .../src/main/resources/camel-context-test.xml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 messaging-modules/apache-camel/src/main/resources/camel-context-test.xml diff --git a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml deleted file mode 100644 index f306574868..0000000000 --- a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From a34c8794edc009b8fa9c46bd4da43726d566a243 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Wed, 20 Sep 2023 17:41:47 +0330 Subject: [PATCH 019/135] #BAEL-6916: add Spring Boot main class --- .../java/com/baeldung/camel/apache/Application.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java new file mode 100755 index 0000000000..51b2540aa8 --- /dev/null +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.camel.apache; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file From 85ac5582781c704284fb61b0d26dd8620c42a88c Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Wed, 20 Sep 2023 17:53:35 +0330 Subject: [PATCH 020/135] #BAEL-6916: add Spring Bean Annotation --- .../main/java/com/baeldung/camel/apache/file/FileProcessor.java | 2 ++ .../main/java/com/baeldung/camel/apache/file/FileRouter.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index ce4d92e8ab..5ca8cc9d72 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -5,7 +5,9 @@ import java.util.Date; import org.apache.camel.Exchange; import org.apache.camel.Processor; +import org.springframework.stereotype.Component; +@Component public class FileProcessor implements Processor { public void process(Exchange exchange) throws Exception { diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java index 760f37677b..b57232d41e 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java @@ -1,7 +1,9 @@ package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; +@Component public class FileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; From 036531949f12f019c1902cfac2e32ed33227de10 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Wed, 20 Sep 2023 17:58:00 +0330 Subject: [PATCH 021/135] #BAEL-6916: add dependencies --- messaging-modules/apache-camel/pom.xml | 60 +++++++++++++++++++++----- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/messaging-modules/apache-camel/pom.xml b/messaging-modules/apache-camel/pom.xml index bb20f178aa..026983484b 100644 --- a/messaging-modules/apache-camel/pom.xml +++ b/messaging-modules/apache-camel/pom.xml @@ -17,30 +17,68 @@ - org.apache.camel - camel-core - ${env.camel.version} + org.springframework.boot + spring-boot-starter-web + + + org.apache.camel.springboot + camel-spring-boot-starter + ${camel.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + org.apache.camel - camel-spring-javaconfig - ${env.camel.version} + camel-test-spring-junit5 + ${camel.version} + test org.apache.camel - camel-jackson - ${env.camel.version} + camel-http + ${camel.version} - org.apache.camel - camel-test - ${env.camel.version} + org.apache.camel.springboot + camel-bindy-starter + ${camel.version} + + + org.apache.camel.springboot + camel-jackson-starter + ${camel.version} + + + org.junit.platform + junit-platform-launcher test - 3.14.7 + 3.21.0 + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + \ No newline at end of file From d48a45c15a23a5b2723aec06fe321ef5359cf4ad Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Wed, 20 Sep 2023 18:00:31 +0330 Subject: [PATCH 022/135] #BAEL-6916: update test cases --- .../FruitArrayJacksonUnmarshalUnitTest.java | 65 ++++++++++++------- .../FruitListJacksonUnmarshalUnitTest.java | 64 +++++++++++------- .../FileProcessorIntegrationTest.java | 11 ++-- 3 files changed, 90 insertions(+), 50 deletions(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index bc0025b263..a5981ccb1a 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -1,5 +1,21 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.ListJacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.test.annotation.DirtiesContext; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; @@ -7,25 +23,42 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.ListJacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; +@CamelSpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@SpringBootTest(classes = {Application.class, FruitArrayJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitArrayJacksonUnmarshalUnitTest { -public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitArray_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(List.class); String json = readJsonFromFile("/json/fruit-array.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); @SuppressWarnings("unchecked") List fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(List.class); @@ -41,18 +74,6 @@ public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit name", "Apple", fruit.getName()); assertEquals("Fruit id", 101, fruit.getId()); } - - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - - from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) - .to("mock:marshalledObject"); - } - }; - } private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitArrayJacksonUnmarshalUnitTest.class.getResource(path); diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index 2d15ebf46b..b5b0fee2f9 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -1,5 +1,21 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import com.baeldung.camel.apache.jackson.FruitList; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.JacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; @@ -7,26 +23,41 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.JacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; -import com.baeldung.camel.apache.jackson.FruitList; +@CamelSpringBootTest +@SpringBootTest(classes = {Application.class, FruitListJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitListJacksonUnmarshalUnitTest { -public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitList_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(FruitList.class); String json = readJsonFromFile("/json/fruit-list.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); FruitList fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(FruitList.class); assertNotNull("Fruit lists should not be null", fruitList); @@ -43,17 +74,6 @@ public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit id", 101, fruit.getId()); } - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) - .to("mock:marshalledObject"); - } - }; - } - private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitListJacksonUnmarshalUnitTest.class.getResource(path); return new String(Files.readAllBytes(Paths.get(resource.toURI()))); diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index e4390a95e5..5df7543c6f 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -1,16 +1,14 @@ package com.apache.camel.file.processor; -import java.io.File; - +import com.baeldung.camel.apache.file.FileProcessor; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.baeldung.camel.apache.file.FileProcessor; +import java.io.File; public class FileProcessorIntegrationTest { @@ -67,9 +65,10 @@ public class FileProcessorIntegrationTest { @Test public void moveFolderContentSpringDSLTest() throws InterruptedException { - ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); +// ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); +// ApplicationContext applicationContext = ContextLoader.getCurrentWebApplicationContext(); Thread.sleep(DURATION_MILIS); - applicationContext.close(); + //applicationContext.close(); } } \ No newline at end of file From 910be42d8f37266fc4d764ba8dbf9646f5066f3e Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Wed, 20 Sep 2023 22:05:22 +0530 Subject: [PATCH 023/135] Review Comment changes --- .../multiple/objecttypes/AlternativeMultipeTypeList.java | 7 +++++-- .../baeldung/list/multiple/objecttypes/CustomObject.java | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java index d80f4627d3..6dd44e0ffa 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java @@ -25,8 +25,8 @@ public class AlternativeMultipeTypeList { // List of Custom Object ArrayList objList = new ArrayList<>(); - objList.add(new CustomObject("obj1", 1)); - objList.add(new CustomObject("obj2", 2)); + objList.add(new CustomObject("String")); + objList.add(new CustomObject(2)); // List via Functional Interface List dataList = new ArrayList<>(); @@ -36,6 +36,9 @@ public class AlternativeMultipeTypeList { UserFunctionalInterface myInterface = (listObj, data) -> { if (myPricate.test(data)) listObj.add(data); + else + System.out.println("Skipping input as data not allowed for class: " + data.getClass() + .getSimpleName()); return listObj; }; diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java index f4d4be989d..eec81523f4 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java @@ -8,8 +8,7 @@ public class CustomObject { this.classData = classData; } - CustomObject(String classData, Integer intData) { - this.classData = classData; + CustomObject(Integer intData) { this.intData = intData; } From a7940d9658d262bf3671c99753b2d4ab8eead674 Mon Sep 17 00:00:00 2001 From: mcasari Date: Thu, 21 Sep 2023 20:28:15 +0200 Subject: [PATCH 024/135] BAEL-6846 - Convert from float to BigDecimal --- convert-float-to-bigdecimal/README.md | 7 ----- convert-float-to-bigdecimal/pom.xml | 16 ---------- .../src/main/resources/logback.xml | 14 --------- .../FloatToBigDecimalUnitTest.java | 24 ++++++++++---- shallow-deep-copy/README.md | 7 ----- shallow-deep-copy/pom.xml | 16 ---------- .../baeldung/shallowdeepcopy/Dependency.java | 23 -------------- .../com/baeldung/shallowdeepcopy/Main.java | 31 ------------------- .../src/main/resources/logback.xml | 14 --------- .../ShallowDeepCopyUnitTest.java | 28 ----------------- 10 files changed, 18 insertions(+), 162 deletions(-) delete mode 100644 convert-float-to-bigdecimal/README.md delete mode 100644 convert-float-to-bigdecimal/pom.xml delete mode 100644 convert-float-to-bigdecimal/src/main/resources/logback.xml rename convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java => core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java (69%) delete mode 100644 shallow-deep-copy/README.md delete mode 100644 shallow-deep-copy/pom.xml delete mode 100644 shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java delete mode 100644 shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java delete mode 100644 shallow-deep-copy/src/main/resources/logback.xml delete mode 100644 shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java diff --git a/convert-float-to-bigdecimal/README.md b/convert-float-to-bigdecimal/README.md deleted file mode 100644 index e01c981831..0000000000 --- a/convert-float-to-bigdecimal/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## Shallow vs Deep Copy - -This module contains an article about converting float to BigDecimal in Java - -### Relevant articles: - -- [Converting from Float to BigDecimal in Java](https://drafts.baeldung.com/?p=175240&preview=true) diff --git a/convert-float-to-bigdecimal/pom.xml b/convert-float-to-bigdecimal/pom.xml deleted file mode 100644 index 8fa20b300f..0000000000 --- a/convert-float-to-bigdecimal/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - 4.0.0 - convert-float-to-bigdecimal - convert-float-to-bigdecimal - jar - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - \ No newline at end of file diff --git a/convert-float-to-bigdecimal/src/main/resources/logback.xml b/convert-float-to-bigdecimal/src/main/resources/logback.xml deleted file mode 100644 index 830ab22727..0000000000 --- a/convert-float-to-bigdecimal/src/main/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java similarity index 69% rename from convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java rename to core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index c43d2ab87a..20422edbd7 100644 --- a/convert-float-to-bigdecimal/src/test/java/com/baeldung/convertfloattobigdecimal/ConvertFloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.convertfloattobigdecimal; +package com.baeldung.floattobigdecimal; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -7,7 +7,7 @@ import java.math.BigDecimal; import org.junit.jupiter.api.Test; -class ConvertFloatToBigDecimalUnitTest { +class FloatToBigDecimalUnitTest { @Test public void whenFloatComparedWithDifferentValues_thenCouldMatch() { @@ -16,12 +16,16 @@ class ConvertFloatToBigDecimalUnitTest { } @Test - public void whenCreatedFromFloat_thenCouldNotMatch() { + public void whenCreatedFromCertainFloatValues_thenMatches() { float floatToConvert = 0.5f; BigDecimal bdFromFloat = new BigDecimal(floatToConvert); assertEquals("0.5", bdFromFloat.toString()); - floatToConvert = 1.1f; - bdFromFloat = new BigDecimal(floatToConvert); + } + + @Test + public void whenCreatedFromCertainFloatValues_thenDoesNotMatch() { + float floatToConvert = 1.1f; + BigDecimal bdFromFloat = new BigDecimal(floatToConvert); assertNotEquals("1.1", bdFromFloat.toString()); } @@ -39,10 +43,18 @@ class ConvertFloatToBigDecimalUnitTest { assertNotEquals("1.1", bdByValueOf.toString()); } + @Test + public void whenFloatCastToDouble_thenGotADifferentNumber() { + float floatToConvert = 1.1f; + double doubleCast = floatToConvert; + assertEquals("1.100000023841858", Double.toString(doubleCast)); + } + @Test public void whenCreatedByValueOfAndIsDouble_thenMatches() { double doubleToConvert = 1.1d; BigDecimal bdByValueOf = BigDecimal.valueOf(doubleToConvert); assertEquals("1.1", bdByValueOf.toString()); } -} + +} \ No newline at end of file diff --git a/shallow-deep-copy/README.md b/shallow-deep-copy/README.md deleted file mode 100644 index e1a426a138..0000000000 --- a/shallow-deep-copy/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## Shallow vs Deep Copy - -This module contains an article about shallow vs deep copy of Java objects - -### Relevant articles: - -- [Creating a deep vs shallow copy of an object in Java](https://drafts.baeldung.com/?p=172294&preview=true) diff --git a/shallow-deep-copy/pom.xml b/shallow-deep-copy/pom.xml deleted file mode 100644 index 323f720df3..0000000000 --- a/shallow-deep-copy/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - 4.0.0 - shallow-deep-copy - shallow-deep-copy - jar - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - \ No newline at end of file diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java deleted file mode 100644 index 2550acd268..0000000000 --- a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Dependency.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.baeldung.shallowdeepcopy; - -public class Dependency implements Cloneable { - private int value = 13; - - public Dependency(int value) { - super(); - this.value = value; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } -} diff --git a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java b/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java deleted file mode 100644 index 33d565bb10..0000000000 --- a/shallow-deep-copy/src/main/java/com/baeldung/shallowdeepcopy/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.shallowdeepcopy; - -public class Main implements Cloneable { - private Dependency dependency; - - public Main(Dependency dependency) { - super(); - this.dependency = dependency; - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - public Object deepClone() throws CloneNotSupportedException { - Main dependentClone = (Main) super.clone(); - Dependency dependencyClone = (Dependency) this.dependency.clone(); - dependentClone.setDependency(dependencyClone); - return dependentClone; - } - - public Dependency getDependency() { - return dependency; - } - - public void setDependency(Dependency dependency) { - this.dependency = dependency; - } - -} diff --git a/shallow-deep-copy/src/main/resources/logback.xml b/shallow-deep-copy/src/main/resources/logback.xml deleted file mode 100644 index 830ab22727..0000000000 --- a/shallow-deep-copy/src/main/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java b/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java deleted file mode 100644 index f75bbc040b..0000000000 --- a/shallow-deep-copy/src/test/java/com/baeldung/shallowdeepcopy/ShallowDeepCopyUnitTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.shallowdeepcopy; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -class ShallowDeepCopyUnitTest { - - @Test - public void givenAnObjectAndADependency_whenShallowClonedAndDepencyChanges_ThenDepencyHasNewValue() throws Exception { - Dependency dependency = new Dependency(13); - Main main = new Main(dependency); - Main shallowClone = (Main) main.clone(); - dependency.setValue(17); - assertEquals(17, shallowClone.getDependency() - .getValue()); - } - - @Test - public void givenAnObjectAndADependency_whenDeepClonedAndDepencyChanges_ThenDepencyKeepsOldValue() throws Exception { - Dependency dependency = new Dependency(13); - Main main = new Main(dependency); - Main deepClone = (Main) main.deepClone(); - dependency.setValue(17); - assertEquals(13, deepClone.getDependency() - .getValue()); - } -} From efab8b66cfb5ae6ab123f815ec19e9b70cd92159 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 22 Sep 2023 11:21:24 +0530 Subject: [PATCH 025/135] Removing Maven Plugin --- .../pom.xml | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index b0622368ad..9d8d7533b5 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -8,31 +8,4 @@ core-java-modules 0.0.1-SNAPSHOT - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven-compiler-plugin.source} - ${maven-compiler-plugin.target} - - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire.plugin.version} - - - --add-opens java.base/java.util=ALL-UNNAMED - - - - - - - 16 - 16 - 3.0.0-M3 - \ No newline at end of file From 2b7c4f684d9edbb5ef2764ae62462c48d99dee6a Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 22 Sep 2023 11:29:41 +0530 Subject: [PATCH 026/135] Removal of Surefire and Upgrading to JDK17 --- .../core-java-collections-array-list-2/pom.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index 9d8d7533b5..c9dd68b457 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -8,4 +8,20 @@ core-java-modules 0.0.1-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + + + 17 + 17 + \ No newline at end of file From 65d94649f10dd91165f31b14fb428477929c2afd Mon Sep 17 00:00:00 2001 From: panos-kakos Date: Fri, 22 Sep 2023 16:37:25 +0300 Subject: [PATCH 027/135] [JAVA-22209] Upgraded spring-cloud-netflix-feign module to jdk17 --- .../spring-cloud-netflix-feign/pom.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml index f519b6316b..92d66c03df 100644 --- a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml @@ -58,6 +58,20 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + Camden.SR7 8.18.0 From ab389ff0096d6f279fe4ed24752f95bc4b0e213e Mon Sep 17 00:00:00 2001 From: panos-kakos Date: Fri, 22 Sep 2023 16:37:34 +0300 Subject: [PATCH 028/135] [JAVA-22209] Upgraded spring-cloud-netflix-feign module to jdk17 --- pom.xml | 5 ++++- spring-cloud-modules/pom.xml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 86d7d3328c..80a450314d 100644 --- a/pom.xml +++ b/pom.xml @@ -723,10 +723,12 @@ spring-boot-rest spring-drools spring-cloud-modules/spring-cloud-azure + spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow - spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-netflix-feign spring-cloud-modules/spring-cloud-zuul-eureka-integration + spring-exceptions spring-jenkins-pipeline spring-core @@ -1001,6 +1003,7 @@ spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract + spring-cloud-modules/spring-cloud-netflix-feign spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 73276d7e0f..27a5f5363c 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -46,7 +46,7 @@ spring-cloud-eureka-self-preservation spring-cloud-openfeign - spring-cloud-netflix-feign + spring-cloud-netflix-sidecar spring-cloud-sentinel spring-cloud-dapr From 0907865ea61a29f726d90eed034fc60adce8f954 Mon Sep 17 00:00:00 2001 From: panos-kakos Date: Fri, 22 Sep 2023 16:52:18 +0300 Subject: [PATCH 029/135] [JAVA-22209] Upgraded spring-cloud-stream-starters module to jdk17 --- pom.xml | 3 ++- spring-cloud-modules/pom.xml | 2 +- .../spring-cloud-stream-starters/twitterhdfs/pom.xml | 8 +++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 80a450314d..0edd6b2b36 100644 --- a/pom.xml +++ b/pom.xml @@ -727,8 +727,8 @@ spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-stream-starters spring-cloud-modules/spring-cloud-zuul-eureka-integration - spring-exceptions spring-jenkins-pipeline spring-core @@ -1004,6 +1004,7 @@ spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-stream-starters spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 27a5f5363c..b21b208414 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -27,7 +27,7 @@ spring-cloud-gateway spring-cloud-gateway-2 spring-cloud-stream - spring-cloud-stream-starters + spring-cloud-connectors-heroku spring-cloud-aws spring-cloud-consul diff --git a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml index 51e8703e6e..1a19415a3f 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml @@ -61,16 +61,21 @@ org.junit.vintage junit-vintage-engine + + org.codehaus.groovy + groovy + ${groovy.version} + + twitterhdfs org.springframework.boot spring-boot-maven-plugin - twitterhdfs @@ -83,6 +88,7 @@ 4.13.2 5.8.1 2.17.1 + 3.0.8 \ No newline at end of file From b5c06059f031bad344d00259899499c5b0fe5a2a Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Sat, 23 Sep 2023 17:30:40 +0330 Subject: [PATCH 030/135] #BAEL-6916: refactor dependencies --- messaging-modules/apache-camel/pom.xml | 54 +++++--------------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/messaging-modules/apache-camel/pom.xml b/messaging-modules/apache-camel/pom.xml index 026983484b..88c807a86a 100644 --- a/messaging-modules/apache-camel/pom.xml +++ b/messaging-modules/apache-camel/pom.xml @@ -16,69 +16,35 @@ - - org.springframework.boot - spring-boot-starter-web - org.apache.camel.springboot camel-spring-boot-starter ${camel.version} - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.apache.camel - camel-test-spring-junit5 - ${camel.version} - test - - - org.apache.camel - camel-http - ${camel.version} - - - org.apache.camel.springboot - camel-bindy-starter - ${camel.version} - org.apache.camel.springboot camel-jackson-starter ${camel.version} + + org.apache.camel + camel-test-spring-junit5 + ${camel.version} + test + org.junit.platform junit-platform-launcher test + + org.springframework.boot + spring-boot-starter-web + 3.21.0 - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M5 - - - \ No newline at end of file From c56bc04f95f7b9c9929d32f5c02ee359d8535265 Mon Sep 17 00:00:00 2001 From: mcasari Date: Sat, 23 Sep 2023 17:02:20 +0200 Subject: [PATCH 031/135] BAEL-6846 - change assertNotEquals to assertEquals --- .../baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index 20422edbd7..2d6d1ab5d0 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -26,7 +26,7 @@ class FloatToBigDecimalUnitTest { public void whenCreatedFromCertainFloatValues_thenDoesNotMatch() { float floatToConvert = 1.1f; BigDecimal bdFromFloat = new BigDecimal(floatToConvert); - assertNotEquals("1.1", bdFromFloat.toString()); + assertEquals("1.10000002384185791015625", bdFromFloat.toString()); } @Test @@ -40,7 +40,7 @@ class FloatToBigDecimalUnitTest { public void whenCreatedByValueOfAndIsFloat_thenDoesNotMatch() { float floatToConvert = 1.1f; BigDecimal bdByValueOf = BigDecimal.valueOf(floatToConvert); - assertNotEquals("1.1", bdByValueOf.toString()); + assertEquals("1.100000023841858", bdByValueOf.toString()); } @Test From d2ede7f67cf2a1b1347fd29e9d8dff0327a086d5 Mon Sep 17 00:00:00 2001 From: rajatgarg Date: Mon, 25 Sep 2023 01:34:58 +0530 Subject: [PATCH 032/135] Address review comments --- core-java-modules/core-java-io-5/.gitignore | 2 + core-java-modules/core-java-io-5/README.md | 8 +++ core-java-modules/core-java-io-5/pom.xml | 66 +++++++++++++++++++ .../ExtensionFromMimeTypeUnitTest.java | 8 +-- core-java-modules/core-java-io/pom.xml | 13 ---- core-java-modules/pom.xml | 1 + 6 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 core-java-modules/core-java-io-5/.gitignore create mode 100644 core-java-modules/core-java-io-5/README.md create mode 100644 core-java-modules/core-java-io-5/pom.xml rename core-java-modules/{core-java-io => core-java-io-5}/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java (94%) diff --git a/core-java-modules/core-java-io-5/.gitignore b/core-java-modules/core-java-io-5/.gitignore new file mode 100644 index 0000000000..0c0cd871c5 --- /dev/null +++ b/core-java-modules/core-java-io-5/.gitignore @@ -0,0 +1,2 @@ +test-link* +0.* \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/README.md b/core-java-modules/core-java-io-5/README.md new file mode 100644 index 0000000000..6072e0b6d9 --- /dev/null +++ b/core-java-modules/core-java-io-5/README.md @@ -0,0 +1,8 @@ +## Core Java IO + +This module contains articles about core Java input and output (IO) + +### Relevant Articles: + +- [[<-- Prev]](/core-java-modules/core-java-io-4) + diff --git a/core-java-modules/core-java-io-5/pom.xml b/core-java-modules/core-java-io-5/pom.xml new file mode 100644 index 0000000000..11116b071c --- /dev/null +++ b/core-java-modules/core-java-io-5/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + core-java-io-5 + core-java-io-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.tika + tika-core + ${tika.version} + + + net.sf.jmimemagic + jmimemagic + ${jmime-magic.version} + + + org.jodd + jodd-util + ${jodd-util.version} + + + com.j256.simplemagic + simplemagic + ${simplemagic.version} + + + + + core-java-io-5 + + + src/main/resources + true + + + + + maven-compiler-plugin + + 11 + 11 + + + + + + + + 2.8.0 + 0.1.5 + 6.2.1 + 1.17 + + \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java similarity index 94% rename from core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java rename to core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java index 2238cfcafa..6b1fd490a8 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java @@ -11,10 +11,8 @@ import java.util.Map; import java.util.Set; import org.apache.tika.mime.MimeTypeException; - -import org.junit.Test; - import com.j256.simplemagic.ContentType; +import org.junit.Test; public class ExtensionFromMimeTypeUnitTest { private static final String IMAGE_JPEG_MIME_TYPE = "image/jpeg"; @@ -37,14 +35,14 @@ public class ExtensionFromMimeTypeUnitTest { } @Test - public void whenUsingMimetypesFileTypeMap_thenGetFileExtension() { + public void whenUsingSimpleMagic_thenGetFileExtension() { List expectedExtensions = Arrays.asList("jpeg", "jpg", "jpe"); String[] detectedExtensions = ContentType.fromMimeType(IMAGE_JPEG_MIME_TYPE).getFileExtensions(); assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); } @Test - public void whenUsingCustomLogic_thenGetFileExtension() { + public void whenUsingCustomMap_thenGetFileExtension() { Map> mimeExtensionsMap = new HashMap<>(); List expectedExtensions = Arrays.asList(".jpg", ".jpe", ".jpeg"); addMimeExtensions(mimeExtensionsMap, "image/jpeg", ".jpg"); diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index 12e957a3ba..faeddafd81 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -43,17 +43,6 @@ ${angus-activation.version} test - - org.jodd - jodd-util - ${jodd-util.version} - - - com.j256.simplemagic - simplemagic - ${simplemagic.version} - - @@ -153,8 +142,6 @@ 4.4.2 2.1.2 2.0.1 - 6.2.1 - 1.17 \ No newline at end of file diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 34e5204868..bee10854d0 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -108,6 +108,7 @@ core-java-io-2 core-java-io-3 core-java-io-4 + core-java-io-5 core-java-io-apis core-java-io-apis-2 core-java-io-conversions From 083cf15f77b45d8aec79f2d2ea5557b48f751ca5 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 09:05:22 +0330 Subject: [PATCH 033/135] #BAEL-6916: add StandardCharsets --- .../camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java | 3 ++- .../camel/jackson/FruitListJacksonUnmarshalUnitTest.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index a5981ccb1a..df7a57a984 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -19,6 +19,7 @@ import org.springframework.test.annotation.DirtiesContext; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; @@ -77,7 +78,7 @@ public class FruitArrayJacksonUnmarshalUnitTest { private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitArrayJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index b5b0fee2f9..bb31884d11 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; @@ -76,7 +77,7 @@ public class FruitListJacksonUnmarshalUnitTest { private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitListJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } From 2bd5ae21de62df694122a342988b39c89b57cd29 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 09:05:54 +0330 Subject: [PATCH 034/135] #BAEL-6916: add camel-context xml --- .../src/main/resources/camel-context-test.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 messaging-modules/apache-camel/src/main/resources/camel-context-test.xml diff --git a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml new file mode 100644 index 0000000000..f6177c69b5 --- /dev/null +++ b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file From 84efed044f77d8bee9e1f8020d25a6d52590e7ef Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 09:06:22 +0330 Subject: [PATCH 035/135] #BAEL-6916: add awaitility dependency --- messaging-modules/apache-camel/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messaging-modules/apache-camel/pom.xml b/messaging-modules/apache-camel/pom.xml index 88c807a86a..8b49ad4893 100644 --- a/messaging-modules/apache-camel/pom.xml +++ b/messaging-modules/apache-camel/pom.xml @@ -41,6 +41,11 @@ org.springframework.boot spring-boot-starter-web + + org.awaitility + awaitility + test + From d05f27429af683552dc6808413ce44886e5f9ed2 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 09:10:13 +0330 Subject: [PATCH 036/135] #BAEL-6916: change timestamp to date for test assertion --- .../main/java/com/baeldung/camel/apache/file/FileProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index 5ca8cc9d72..c9537d48de 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -14,7 +14,7 @@ public class FileProcessor implements Processor { String originalFileName = (String) exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); Date date = new Date(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String changedFileName = dateFormat.format(date) + originalFileName; exchange.getIn().setHeader(Exchange.FILE_NAME, changedFileName); } From a4aa3a69b7207f076b55aa6df27dc29b33dc7ee7 Mon Sep 17 00:00:00 2001 From: panos-kakos Date: Tue, 26 Sep 2023 08:42:23 +0300 Subject: [PATCH 037/135] [JAVA-25490] Package renaming --- .../com/baeldung/config/scope/AppConfigFunctionBean.java | 2 +- .../src/main/java/com/baeldung/scope/AppConfig.java | 8 ++++---- .../main/java/com/baeldung/scope/AppProxyScopeConfig.java | 2 +- .../java/com/baeldung/scope/BeanInjectionStarter.java | 2 +- .../SingletonAppContextBean.java | 2 +- .../scope/{singletone => singleton}/SingletonBean.java | 2 +- .../{singletone => singleton}/SingletonFunctionBean.java | 2 +- .../{singletone => singleton}/SingletonLookupBean.java | 2 +- .../SingletonObjectFactoryBean.java | 2 +- .../{singletone => singleton}/SingletonProviderBean.java | 2 +- .../scope/PrototypeBeanInjectionIntegrationTest.java | 7 +++---- .../scope/PrototypeFunctionBeanIntegrationTest.java | 2 +- 12 files changed, 17 insertions(+), 18 deletions(-) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonAppContextBean.java (94%) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonBean.java (93%) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonFunctionBean.java (91%) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonLookupBean.java (88%) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonObjectFactoryBean.java (91%) rename spring-core/src/main/java/com/baeldung/scope/{singletone => singleton}/SingletonProviderBean.java (90%) diff --git a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java index a3c5445698..aa526b5403 100644 --- a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java @@ -7,7 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @Configuration public class AppConfigFunctionBean { diff --git a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java index 33a9c5c21e..2ef775ee4f 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java @@ -1,10 +1,10 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonAppContextBean; -import com.baeldung.scope.singletone.SingletonBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonAppContextBean; +import com.baeldung.scope.singleton.SingletonBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; diff --git a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java index 9f1874375e..0564dfb3c0 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.*; diff --git a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java index 5cf0c9170c..47014aa2d1 100644 --- a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java +++ b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.util.Assert; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java similarity index 94% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java index f4d57a0f63..4f5b3274c8 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.BeansException; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java similarity index 93% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java index 8d3a09b8fd..9c4cea4439 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.apache.log4j.Logger; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java index 8cdc56a6fa..2788af1701 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import java.util.function.Function; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java similarity index 88% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java index 4c3c9b69da..e5461826ef 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Lookup; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java index 55a91f8202..0e70d12e6e 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.ObjectFactory; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java similarity index 90% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java index 37d0ad9404..01a4a0ff11 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java index d0c2733765..df04957992 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java @@ -1,10 +1,9 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; -import com.baeldung.scope.singletone.SingletonLookupBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonLookupBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java index 1e3c652599..dac3461ceb 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java @@ -11,7 +11,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.config.scope.AppConfigFunctionBean; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = AppConfigFunctionBean.class) From fa56411bd38477d3d5827c3a9bd3c17fa10a7e78 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 09:13:59 +0330 Subject: [PATCH 038/135] #BAEL-6916: add Awaitility instead of Thread.sleep and given when then --- .../FileProcessorIntegrationTest.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index 5df7543c6f..67273d8a87 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -4,11 +4,18 @@ import com.baeldung.camel.apache.file.FileProcessor; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; +import org.awaitility.Awaitility; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class FileProcessorIntegrationTest { @@ -50,7 +57,7 @@ public class FileProcessorIntegrationTest { } @Test - public void moveFolderContentJavaDSLTest() throws Exception { + public void givenJavaDSLRoute_whenCamelStart_thenMoveFolderContent() throws Exception { final CamelContext camelContext = new DefaultCamelContext(); camelContext.addRoutes(new RouteBuilder() { @Override @@ -59,16 +66,27 @@ public class FileProcessorIntegrationTest { } }); camelContext.start(); - Thread.sleep(DURATION_MILIS); + verifyFolderContent(); camelContext.stop(); } @Test - public void moveFolderContentSpringDSLTest() throws InterruptedException { -// ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); -// ApplicationContext applicationContext = ContextLoader.getCurrentWebApplicationContext(); - Thread.sleep(DURATION_MILIS); - //applicationContext.close(); + public void givenSpringDSLRoute_whenCamelStart_thenMoveFolderContent() throws InterruptedException { + ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); + verifyFolderContent(); + applicationContext.close(); } + + private void verifyFolderContent() { + Date date = new Date(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + File destinationFile1 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File1.txt"); + File destinationFile2 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File2.txt"); + + Awaitility.await().atMost(DURATION_MILIS, TimeUnit.MILLISECONDS).untilAsserted(() -> { + assertThat(destinationFile1.exists()).isTrue(); + assertThat(destinationFile2.exists()).isTrue(); + }); + } } \ No newline at end of file From 6a858656fd9a3e6262edd549f2e4585604067e34 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Tue, 26 Sep 2023 13:53:34 +0330 Subject: [PATCH 039/135] #BAEL-6916: remove extra space --- .../camel/file/processor/FileProcessorIntegrationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index 67273d8a87..5003021d20 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -75,7 +75,6 @@ public class FileProcessorIntegrationTest { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); verifyFolderContent(); applicationContext.close(); - } private void verifyFolderContent() { From ca1e69ae862c4fe85ad9f3dd4d0adb1e5b1d3d56 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Wed, 27 Sep 2023 22:34:49 +0530 Subject: [PATCH 040/135] Review Comments --- .../core-java-collections-array-list-2/README.md | 3 +-- core-java-modules/core-java-collections-array-list-2/pom.xml | 4 +++- .../AlternativeMultipeTypeList.java | 2 +- .../objecttypes => multipleobjecttypes}/CustomObject.java | 2 +- .../MultipleObjectTypeArrayList.java | 2 +- .../UserFunctionalInterface.java | 2 +- core-java-modules/pom.xml | 4 ++-- 7 files changed, 10 insertions(+), 9 deletions(-) rename core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/{multiple/objecttypes => multipleobjecttypes}/AlternativeMultipeTypeList.java (97%) rename core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/{multiple/objecttypes => multipleobjecttypes}/CustomObject.java (88%) rename core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/{multiple/objecttypes => multipleobjecttypes}/MultipleObjectTypeArrayList.java (97%) rename core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/{multiple/objecttypes => multipleobjecttypes}/UserFunctionalInterface.java (91%) diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md index feef70a6dc..00c3e8d9b7 100644 --- a/core-java-modules/core-java-collections-array-list-2/README.md +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -2,5 +2,4 @@ This module contains articles about the Java ArrayList collection -### Relevant Articles: -- [Create an ArrayList with Multiple Object Types](https://drafts.baeldung.com/create-an-arraylist-with-multiple-object-types/) \ No newline at end of file +### Relevant Articles: \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index c9dd68b457..74fda13525 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 core-java-collections-array-list-2 core-java-collections-array-list-2 diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java similarity index 97% rename from core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java index 6dd44e0ffa..f073ea4eab 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/AlternativeMultipeTypeList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java @@ -1,4 +1,4 @@ -package com.baeldung.list.multiple.objecttypes; +package com.baeldung.list.multipleobjecttypes; import java.util.ArrayList; import java.util.HashMap; diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java similarity index 88% rename from core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java index eec81523f4..b3ac4ffddb 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/CustomObject.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java @@ -1,4 +1,4 @@ -package com.baeldung.list.multiple.objecttypes; +package com.baeldung.list.multipleobjecttypes; public class CustomObject { String classData; diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java similarity index 97% rename from core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java index 34610785cb..c5740c5cf8 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/MultipleObjectTypeArrayList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java @@ -1,4 +1,4 @@ -package com.baeldung.list.multiple.objecttypes; +package com.baeldung.list.multipleobjecttypes; import java.math.BigInteger; import java.time.LocalDate; diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java similarity index 91% rename from core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java rename to core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java index 7e39d5a152..6c0f8451da 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multiple/objecttypes/UserFunctionalInterface.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java @@ -1,4 +1,4 @@ -package com.baeldung.list.multiple.objecttypes; +package com.baeldung.list.multipleobjecttypes; import java.util.List; diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 88797a1bf3..c28fb1f78e 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -28,13 +28,14 @@ core-java-9-improvements - core-java-collections-array-list core-java-9-streams core-java-9 core-java-10 core-java-11 core-java-11-2 core-java-11-3 + core-java-collections-array-list + core-java-collections-array-list-2 core-java-collections-list-4 core-java-collections-list-5 core-java-collections-maps-4 @@ -177,7 +178,6 @@ core-java-collections-maps-6 core-java-records core-java-9-jigsaw - core-java-collections-array-list-2 From 5bc91182a507313d604e46ffa8c3c0ddb7a4aac5 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Thu, 28 Sep 2023 11:13:45 +0530 Subject: [PATCH 041/135] Update pom.xml --- core-java-modules/core-java-collections-array-list-2/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index 74fda13525..4138939ea6 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -22,8 +22,9 @@ + 17 17 - \ No newline at end of file + From 20d6dbaef31bd1acb8e0a1baac09f214318b84af Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Thu, 28 Sep 2023 11:14:33 +0530 Subject: [PATCH 042/135] Updating spelling mistake --- .../list/multipleobjecttypes/AlternativeMultipeTypeList.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java index f073ea4eab..5315147dff 100644 --- a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java @@ -31,10 +31,10 @@ public class AlternativeMultipeTypeList { // List via Functional Interface List dataList = new ArrayList<>(); - Predicate myPricate = inputData -> (inputData instanceof String || inputData instanceof Integer); + Predicate myPredicate = inputData -> (inputData instanceof String || inputData instanceof Integer); UserFunctionalInterface myInterface = (listObj, data) -> { - if (myPricate.test(data)) + if (myPredicate.test(data)) listObj.add(data); else System.out.println("Skipping input as data not allowed for class: " + data.getClass() From 15ca62982ffaa9cef6fa0b366807669f75dd3209 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Thu, 28 Sep 2023 11:21:46 +0530 Subject: [PATCH 043/135] Updated pom formatting --- core-java-modules/core-java-collections-array-list-2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index 4138939ea6..d9cadfe622 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -27,4 +27,4 @@ 17 17 - + \ No newline at end of file From 27d104d197a4f6426a70223bec4b118ce1ef13c5 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Thu, 28 Sep 2023 11:55:40 +0530 Subject: [PATCH 044/135] Update pom.xml --- core-java-modules/core-java-collections-array-list-2/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index d9cadfe622..44ecb0fffb 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -10,6 +10,7 @@ core-java-modules 0.0.1-SNAPSHOT + @@ -27,4 +28,4 @@ 17 17 - \ No newline at end of file + From a086bb8bcc3734f54a4e5876350496b78c81c781 Mon Sep 17 00:00:00 2001 From: hmdrz Date: Thu, 28 Sep 2023 10:52:56 +0330 Subject: [PATCH 045/135] #bael-6916:add @Override --- .../main/java/com/baeldung/camel/apache/file/FileProcessor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index c9537d48de..a0571e7083 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -10,6 +10,7 @@ import org.springframework.stereotype.Component; @Component public class FileProcessor implements Processor { + @Override public void process(Exchange exchange) throws Exception { String originalFileName = (String) exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); From a06a2415dbc2ecc7b2e115df2008e264d6cab800 Mon Sep 17 00:00:00 2001 From: Anastasios Ioannidis Date: Thu, 28 Sep 2023 11:33:20 +0300 Subject: [PATCH 046/135] JAVA-13321 New Gateway-2 module with spring-cloud-gateway article's subjects --- .../gateway-2/README.md | 8 +- .../gateway-2/baeldung-realm.json | 2186 ----------------- .../spring-cloud-bootstrap/gateway-2/pom.xml | 132 +- .../CustomFiltersGatewayApplication.java | 15 - .../gatewayapp/config/WebClientConfig.java | 16 - .../ChainRequestGatewayFilterFactory.java | 89 - .../LoggingGatewayFilterFactory.java | 85 - .../ModifyRequestGatewayFilterFactory.java | 92 - .../ModifyResponseGatewayFilterFactory.java | 48 - .../ScrubResponseGatewayFilterFactory.java | 110 - .../global/FirstPreLastPostGlobalFilter.java | 31 - .../global/LoggingGlobalFilterProperties.java | 47 - .../LoggingGlobalFiltersConfigurations.java | 25 - .../global/LoggingGlobalPreFilter.java | 22 - .../routes/ServiceRouteConfiguration.java | 28 - .../SecondServiceApplication.java | 15 - .../web/SecondServiceRestController.java | 18 - .../service/ServiceApplication.java | 15 - .../service/web/ServiceRestController.java | 22 - .../rewrite/URLRewriteGatewayApplication.java | 25 - .../rewrite/routes/DynamicRewriteRoute.java | 43 - .../WebFilterGatewayApplication.java | 15 - .../config/ModifyBodyRouteConfig.java | 49 - .../RequestRateLimiterResolverConfig.java | 16 - .../main/resources/application-nosecurity.yml | 8 - .../src/main/resources/application-scrub.yml | 12 - .../resources/application-url-rewrite.yml | 11 - .../main/resources/application-webfilters.yml | 102 - ...ustomfilters-global-application.properties | 19 - .../secondservice-application.properties | 1 - .../resources/service-application.properties | 1 - .../gatewayapp/CustomFiltersLiveTest.java | 112 - ...bResponseGatewayFilterFactoryUnitTest.java | 61 - .../ScrubResponseGatewayFilterLiveTest.java | 135 - .../SecondServiceIntegrationTest.java | 28 - .../secondservice/SpringContextTest.java | 12 - .../service/ServiceIntegrationTest.java | 31 - .../service/SpringContextTest.java | 12 - .../LoggerListAppender.java | 2 +- .../URLRewriteGatewayApplicationLiveTest.java | 109 - .../RedisWebFilterFactoriesLiveTest.java | 64 - .../WebFilterFactoriesLiveTest.java | 136 - .../OAuth_Gateway.postman_collection.json | 203 -- .../src/test/resources/logback-test.xml | 2 +- 44 files changed, 34 insertions(+), 4179 deletions(-) delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java rename spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/{customfilters/gatewayapp/utils => introduction}/LoggerListAppender.java (88%) delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java delete mode 100644 spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md index 80315040c9..b76ae19f26 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md @@ -4,10 +4,4 @@ This module contains articles about Spring Cloud Gateway ### Relevant Articles: -- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) -- [Writing Custom Spring Cloud Gateway Filters](https://www.baeldung.com/spring-cloud-custom-gateway-filters) -- [Spring Cloud Gateway Routing Predicate Factories](https://www.baeldung.com/spring-cloud-gateway-routing-predicate-factories) -- [Spring Cloud Gateway WebFilter Factories](https://www.baeldung.com/spring-cloud-gateway-webfilter-factories) -- [Using Spring Cloud Gateway with OAuth 2.0 Patterns](https://www.baeldung.com/spring-cloud-gateway-oauth2) -- [URL Rewriting With Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-url-rewriting) -- [Processing the Response Body in Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway-response-body) +- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json deleted file mode 100644 index 4dad262568..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/baeldung-realm.json +++ /dev/null @@ -1,2186 +0,0 @@ -{ - "id": "baeldung", - "realm": "baeldung", - "notBefore": 0, - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "clientSessionIdleTimeout": 0, - "clientSessionMaxLifespan": 0, - "clientOfflineSessionIdleTimeout": 0, - "clientOfflineSessionMaxLifespan": 0, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, - "enabled": true, - "sslRequired": "external", - "registrationAllowed": false, - "registrationEmailAsUsername": false, - "rememberMe": false, - "verifyEmail": false, - "loginWithEmailAllowed": true, - "duplicateEmailsAllowed": false, - "resetPasswordAllowed": false, - "editUsernameAllowed": false, - "bruteForceProtected": false, - "permanentLockout": false, - "maxFailureWaitSeconds": 900, - "minimumQuickLoginWaitSeconds": 60, - "waitIncrementSeconds": 60, - "quickLoginCheckMilliSeconds": 1000, - "maxDeltaTimeSeconds": 43200, - "failureFactor": 30, - "roles": { - "realm": [ - { - "id": "2f721e46-398b-43ff-845f-3c747f1f69f5", - "name": "standard", - "description": "Standard customer", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - }, - { - "id": "b8b1cb49-c953-4cb0-acea-62b24c4b6d30", - "name": "silver", - "description": "Silver customer", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - }, - { - "id": "f44f5ba9-2393-4d2a-b581-81cf8dd7f245", - "name": "gold", - "description": "Gold customers", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - }, - { - "id": "3b6109f5-6e5a-4578-83c3-791ec3e2bf9e", - "name": "offline_access", - "description": "${role_offline-access}", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - }, - { - "id": "0dd6a8c7-d669-4941-9ea1-521980e9c53f", - "name": "uma_authorization", - "description": "${role_uma_authorization}", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - }, - { - "id": "ca962095-7f9b-49e2-a190-e391a0d4b704", - "name": "user", - "composite": false, - "clientRole": false, - "containerId": "baeldung", - "attributes": {} - } - ], - "client": { - "newClient": [], - "realm-management": [ - { - "id": "5d00243f-ceec-4b0c-995e-d86d5b8a0ae6", - "name": "view-clients", - "description": "${role_view-clients}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "query-clients" - ] - } - }, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "941612de-bd85-47a5-8dfa-37c270dde28c", - "name": "view-authorization", - "description": "${role_view-authorization}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "5ea9810d-63cc-4277-9b32-ba8a3d3c6091", - "name": "manage-realm", - "description": "${role_manage-realm}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "8b7b0dd8-350b-473e-b8cd-8acad34f1358", - "name": "query-clients", - "description": "${role_query-clients}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "0f8e5ee8-b014-4b7c-9b69-50f46abcba5f", - "name": "query-groups", - "description": "${role_query-groups}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "911b1489-9383-4734-b134-bf49bf992ce9", - "name": "manage-clients", - "description": "${role_manage-clients}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "5d48274c-bd6b-4c26-ad54-f1a2254beac0", - "name": "view-realm", - "description": "${role_view-realm}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "3ea43b64-316f-4693-8346-9ee78b24adaf", - "name": "manage-identity-providers", - "description": "${role_manage-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "49735614-96ec-49b2-98fe-3af9bcd1a33a", - "name": "create-client", - "description": "${role_create-client}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "e8f8c3cc-0ff1-4f72-a271-db6821a3cdb6", - "name": "manage-users", - "description": "${role_manage-users}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "387418b1-4f80-4b00-b9dd-805ca041f805", - "name": "view-identity-providers", - "description": "${role_view-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "427c27d4-521a-464b-a0df-16d7f537e8d5", - "name": "realm-admin", - "description": "${role_realm-admin}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "view-clients", - "view-authorization", - "query-groups", - "manage-realm", - "query-clients", - "manage-clients", - "view-realm", - "manage-identity-providers", - "create-client", - "manage-users", - "view-identity-providers", - "query-users", - "query-realms", - "view-users", - "impersonation", - "manage-authorization", - "manage-events", - "view-events" - ] - } - }, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "a574cf01-03e4-4573-ab9e-276d13a1ce8d", - "name": "query-users", - "description": "${role_query-users}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "c3a253a8-a1b6-4d38-9677-f728f32482ad", - "name": "query-realms", - "description": "${role_query-realms}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "f3cb93da-273e-419a-b2f4-93f09896abcf", - "name": "view-users", - "description": "${role_view-users}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "query-users", - "query-groups" - ] - } - }, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "6eedf2b7-50ef-4495-a89b-54aef751b7fa", - "name": "manage-authorization", - "description": "${role_manage-authorization}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "0332e99b-3dfc-4193-9e13-5728f8f3e6d6", - "name": "impersonation", - "description": "${role_impersonation}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "b690cb9c-0f4a-4be5-ade0-b40443d8149d", - "name": "view-events", - "description": "${role_view-events}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - }, - { - "id": "aac3def5-f193-4a6c-9065-1667a0746a8a", - "name": "manage-events", - "description": "${role_manage-events}", - "composite": false, - "clientRole": true, - "containerId": "6a4bfbd0-576d-4778-af56-56f876647355", - "attributes": {} - } - ], - "security-admin-console": [], - "quotes-client": [], - "admin-cli": [], - "account-console": [], - "broker": [ - { - "id": "397b5703-4c81-48fd-a24c-a7e8177ef657", - "name": "read-token", - "description": "${role_read-token}", - "composite": false, - "clientRole": true, - "containerId": "4b9609f0-48d1-4e71-9381-2ecec08616f9", - "attributes": {} - } - ], - "account": [ - { - "id": "8daa8096-d14e-4d1c-ad1f-83f822016aa1", - "name": "manage-account", - "description": "${role_manage-account}", - "composite": true, - "composites": { - "client": { - "account": [ - "manage-account-links" - ] - } - }, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - }, - { - "id": "15f0d8be-932b-4565-8ad0-e8aa170093dd", - "name": "view-consent", - "description": "${role_view-consent}", - "composite": false, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - }, - { - "id": "c5aa697c-bf87-47c6-bd94-9121b72420b9", - "name": "view-applications", - "description": "${role_view-applications}", - "composite": false, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - }, - { - "id": "f0b3bbe4-aec1-4227-b9d3-2c314d612a04", - "name": "manage-consent", - "description": "${role_manage-consent}", - "composite": true, - "composites": { - "client": { - "account": [ - "view-consent" - ] - } - }, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - }, - { - "id": "948269c7-a69c-4c82-a7f3-88868713dfd9", - "name": "manage-account-links", - "description": "${role_manage-account-links}", - "composite": false, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - }, - { - "id": "aed18201-2433-4998-8fa3-0979b0b31c10", - "name": "view-profile", - "description": "${role_view-profile}", - "composite": false, - "clientRole": true, - "containerId": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "attributes": {} - } - ] - } - }, - "groups": [ - { - "id": "635c3314-f15f-4c02-bcb7-8739fd4c21b7", - "name": "golden_customers", - "path": "/golden_customers", - "attributes": {}, - "realmRoles": [ - "gold" - ], - "clientRoles": {}, - "subGroups": [] - }, - { - "id": "279c5ec4-0588-4884-91c1-2697ed5c9826", - "name": "silver_customers", - "path": "/silver_customers", - "attributes": {}, - "realmRoles": [ - "silver" - ], - "clientRoles": {}, - "subGroups": [] - } - ], - "defaultRoles": [ - "uma_authorization", - "offline_access" - ], - "requiredCredentials": [ - "password" - ], - "otpPolicyType": "totp", - "otpPolicyAlgorithm": "HmacSHA1", - "otpPolicyInitialCounter": 0, - "otpPolicyDigits": 6, - "otpPolicyLookAheadWindow": 1, - "otpPolicyPeriod": 30, - "otpSupportedApplications": [ - "FreeOTP", - "Google Authenticator" - ], - "webAuthnPolicyRpEntityName": "keycloak", - "webAuthnPolicySignatureAlgorithms": [ - "ES256" - ], - "webAuthnPolicyRpId": "", - "webAuthnPolicyAttestationConveyancePreference": "not specified", - "webAuthnPolicyAuthenticatorAttachment": "not specified", - "webAuthnPolicyRequireResidentKey": "not specified", - "webAuthnPolicyUserVerificationRequirement": "not specified", - "webAuthnPolicyCreateTimeout": 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyAcceptableAaguids": [], - "webAuthnPolicyPasswordlessRpEntityName": "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms": [ - "ES256" - ], - "webAuthnPolicyPasswordlessRpId": "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", - "webAuthnPolicyPasswordlessCreateTimeout": 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyPasswordlessAcceptableAaguids": [], - "scopeMappings": [ - { - "clientScope": "offline_access", - "roles": [ - "offline_access" - ] - } - ], - "clientScopeMappings": { - "account": [ - { - "client": "account-console", - "roles": [ - "manage-account" - ] - } - ] - }, - "clients": [ - { - "id": "12eebf0b-a3eb-49f8-9ecf-173cf8a00145", - "clientId": "account", - "name": "${client_account}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/baeldung/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "defaultRoles": [ - "manage-account", - "view-profile" - ], - "redirectUris": [ - "/realms/baeldung/account/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "8209784b-8540-43c2-aece-241acf12ea5a", - "clientId": "account-console", - "name": "${client_account-console}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/baeldung/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [ - "/realms/baeldung/account/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "58395b96-1718-4787-8f92-74577e2bfc30", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - } - ], - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "13d76feb-d762-4409-bb84-7a75bc395a61", - "clientId": "admin-cli", - "name": "${client_admin-cli}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": false, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "4b9609f0-48d1-4e71-9381-2ecec08616f9", - "clientId": "broker", - "name": "${client_broker}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "b88ce206-63d6-43b6-87c9-ea09d8c02f32", - "clientId": "newClient", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [ - "http://localhost:8082/new-client/login/oauth2/code/custom", - "http://localhost:8089/", - "http://localhost:8089/auth/redirect/" - ], - "webOrigins": [ - "+" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": true, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": [ - "role_list", - "profile" - ], - "optionalClientScopes": [ - "web-origins", - "address", - "read", - "phone", - "roles", - "offline_access", - "microprofile-jwt", - "write", - "email" - ] - }, - { - "id": "5898f71f-b91e-4c3f-9c86-48de0e8665c4", - "clientId": "quotes-client", - "name": "Quotes Client", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "0e082231-a70d-48e8-b8a5-fbfb743041b6", - "redirectUris": [ - "http://localhost:8082/*", - "http://localhost:8087/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.multivalued.roles": "false", - "saml.force.post.binding": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "protocolMappers": [ - { - "id": "008d32b5-ea7b-4739-89af-e90fe137bda9", - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String", - "multivalued": "true" - } - } - ], - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "6a4bfbd0-576d-4778-af56-56f876647355", - "clientId": "realm-management", - "name": "${client_realm-management}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "8e358d2f-b085-4243-8e6e-c175431e5eeb", - "clientId": "security-admin-console", - "name": "${client_security-admin-console}", - "rootUrl": "${authAdminUrl}", - "baseUrl": "/admin/baeldung/console/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [ - "/admin/baeldung/console/*" - ], - "webOrigins": [ - "+" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "9cfca9ee-493d-4b5e-8170-2d364149de59", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - } - ], - "clientScopes": [ - { - "id": "77c7e29d-1a22-4419-bbfb-4a62bb033449", - "name": "address", - "description": "OpenID Connect built-in scope: address", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "94e1879d-b49e-4178-96e0-bf8d7f32c160", - "name": "address", - "protocol": "openid-connect", - "protocolMapper": "oidc-address-mapper", - "consentRequired": false, - "config": { - "user.attribute.formatted": "formatted", - "user.attribute.country": "country", - "user.attribute.postal_code": "postal_code", - "userinfo.token.claim": "true", - "user.attribute.street": "street", - "id.token.claim": "true", - "user.attribute.region": "region", - "access.token.claim": "true", - "user.attribute.locality": "locality" - } - } - ] - }, - { - "id": "b3526ac1-10e2-4344-8621-9c5a0853e97a", - "name": "email", - "description": "OpenID Connect built-in scope: email", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "d30270dc-baa6-455a-8ff6-ddccf8a78d86", - "name": "email verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "emailVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email_verified", - "jsonType.label": "boolean" - } - }, - { - "id": "f5b1684d-e479-4134-8578-457fa64717da", - "name": "email", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "email", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "c658ae14-e96a-4745-b21b-2ed5c4c63f5f", - "name": "microprofile-jwt", - "description": "Microprofile - JWT built-in scope", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "959521bc-5ffd-465b-95f2-5b0c20d1909c", - "name": "upn", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "upn", - "jsonType.label": "String" - } - }, - { - "id": "07b8550c-b298-4cce-9ffb-900182575b76", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "userinfo.token.claim": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "569b3d44-4ecd-4768-a58c-70ff38f4b4fe", - "name": "offline_access", - "description": "OpenID Connect built-in scope: offline_access", - "protocol": "openid-connect", - "attributes": { - "consent.screen.text": "${offlineAccessScopeConsentText}", - "display.on.consent.screen": "true" - } - }, - { - "id": "a3e7b19d-df6c-437e-9eea-06fec1becb2f", - "name": "phone", - "description": "OpenID Connect built-in scope: phone", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${phoneScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "72a070f7-4363-4c88-8153-6fd2d12b9b04", - "name": "phone number verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumberVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number_verified", - "jsonType.label": "boolean" - } - }, - { - "id": "24b42c6d-a93c-4aa1-9a03-2a2b55954c13", - "name": "phone number", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumber", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "ba8c9950-fd0b-4434-8be6-b58456d7b6d4", - "name": "profile", - "description": "OpenID Connect built-in scope: profile", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "0a9ddd71-309c-40f0-8ea6-a0791070c6ed", - "name": "profile", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "profile", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "profile", - "jsonType.label": "String" - } - }, - { - "id": "fbf53bbd-1ad0-4bf8-8030-50f81696d8ee", - "name": "nickname", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "nickname", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "nickname", - "jsonType.label": "String" - } - }, - { - "id": "423be2cd-42c0-462e-9030-18f9b28ff2d3", - "name": "gender", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "gender", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "gender", - "jsonType.label": "String" - } - }, - { - "id": "53eb9006-4b81-474a-8b60-80f775d54b63", - "name": "picture", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "picture", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "picture", - "jsonType.label": "String" - } - }, - { - "id": "4d8bc82a-eaeb-499e-8eb2-0f1dcbe91699", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - }, - { - "id": "d3b25485-4042-419d-afff-cfd63a76e229", - "name": "full name", - "protocol": "openid-connect", - "protocolMapper": "oidc-full-name-mapper", - "consentRequired": false, - "config": { - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - }, - { - "id": "422cfa5a-f2f4-4f36-82df-91b47ae1ea50", - "name": "given name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "firstName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "given_name", - "jsonType.label": "String" - } - }, - { - "id": "3f2863c1-d98d-45b5-b08f-af9c4d9c10f8", - "name": "website", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "website", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "website", - "jsonType.label": "String" - } - }, - { - "id": "c98c063d-eee4-41a0-9130-595afd709d1f", - "name": "middle name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "middleName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "middle_name", - "jsonType.label": "String" - } - }, - { - "id": "8dbed80a-d672-4185-8dda-4bba2a56ec83", - "name": "family name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "lastName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "family_name", - "jsonType.label": "String" - } - }, - { - "id": "5e5c690c-93cf-489d-a054-b109eab8911b", - "name": "updated at", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "updatedAt", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "updated_at", - "jsonType.label": "String" - } - }, - { - "id": "3b985202-af8a-42f1-ac5f-0966a404f5d7", - "name": "birthdate", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "birthdate", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "birthdate", - "jsonType.label": "String" - } - }, - { - "id": "6eafd1b3-7121-4919-ad1e-039fa58acc32", - "name": "username", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "preferred_username", - "jsonType.label": "String" - } - }, - { - "id": "73cba925-8c31-443f-9601-b1514e6396c1", - "name": "zoneinfo", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "zoneinfo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "zoneinfo", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "c1a2eb23-25c6-4be7-a791-bbdca99c83f7", - "name": "read", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true" - } - }, - { - "id": "18e141bf-dabe-4858-879c-dbc439cdead4", - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [ - { - "id": "10cbe37f-0198-4d65-bc8a-bfe5ad8145d1", - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - } - ] - }, - { - "id": "111ed87a-5fd3-4cee-96df-8dbfb88cfdc0", - "name": "roles", - "description": "OpenID Connect scope for add user roles to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "24924d8d-6071-4a93-b40f-326176cb335e", - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String", - "multivalued": "true" - } - }, - { - "id": "2f6a9bdf-3758-484c-996d-e4f93555559f", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - }, - { - "id": "804d4798-d9a3-4fd3-8b28-d12142e8cb3d", - "name": "client roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-client-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "resource_access.${client_id}.roles", - "jsonType.label": "String", - "multivalued": "true" - } - } - ] - }, - { - "id": "51d49314-b511-43e0-9258-bfb873758a78", - "name": "web-origins", - "description": "OpenID Connect scope for add allowed web origins to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false", - "consent.screen.text": "" - }, - "protocolMappers": [ - { - "id": "2b384cd0-9e85-4a87-8eeb-2b480b0587b7", - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": {} - } - ] - }, - { - "id": "c3e253fb-7361-47cf-9d4a-86245686fdf1", - "name": "write", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true" - } - } - ], - "defaultDefaultClientScopes": [ - "roles", - "role_list", - "web-origins", - "email", - "profile" - ], - "defaultOptionalClientScopes": [ - "offline_access", - "address", - "phone", - "microprofile-jwt" - ], - "browserSecurityHeaders": { - "contentSecurityPolicyReportOnly": "", - "xContentTypeOptions": "nosniff", - "xRobotsTag": "none", - "xFrameOptions": "SAMEORIGIN", - "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection": "1; mode=block", - "strictTransportSecurity": "max-age=31536000; includeSubDomains" - }, - "smtpServer": {}, - "eventsEnabled": false, - "eventsListeners": [ - "jboss-logging" - ], - "enabledEventTypes": [], - "adminEventsEnabled": false, - "adminEventsDetailsEnabled": false, - "components": { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ - { - "id": "84305f42-4b6d-4b0a-ac7c-53e406e3ac63", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "c7c38a95-744f-4558-a403-9cf692fe1944", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "365b2899-befe-4417-b89b-562650ec4446", - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "81c32244-7921-43e9-9356-a3469259b78c", - "name": "Trusted Hosts", - "providerId": "trusted-hosts", - "subType": "anonymous", - "subComponents": {}, - "config": { - "host-sending-registration-request-must-match": [ - "true" - ], - "client-uris-must-match": [ - "true" - ] - } - }, - { - "id": "d09b2147-afea-4f7f-a49c-0aec7eee10de", - "name": "Max Clients Limit", - "providerId": "max-clients", - "subType": "anonymous", - "subComponents": {}, - "config": { - "max-clients": [ - "200" - ] - } - }, - { - "id": "41ffde1b-72a2-416f-87a7-94989e940dc0", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "saml-user-property-mapper", - "oidc-address-mapper", - "oidc-usermodel-property-mapper", - "oidc-full-name-mapper", - "oidc-sha256-pairwise-sub-mapper", - "saml-role-list-mapper", - "oidc-usermodel-attribute-mapper", - "saml-user-attribute-mapper" - ] - } - }, - { - "id": "76075388-2782-4656-a986-313493239a9f", - "name": "Consent Required", - "providerId": "consent-required", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "3caaf57a-9cd7-48c1-b709-b40b887414f7", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-usermodel-attribute-mapper", - "saml-user-property-mapper", - "oidc-usermodel-property-mapper", - "oidc-full-name-mapper", - "saml-user-attribute-mapper", - "oidc-address-mapper", - "saml-role-list-mapper", - "oidc-sha256-pairwise-sub-mapper" - ] - } - } - ], - "org.keycloak.keys.KeyProvider": [ - { - "id": "d67a940a-52e4-44a5-9f69-6ffdd67a188f", - "name": "rsa-generated", - "providerId": "rsa-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "48d40de3-6234-42e8-9449-f68f56abb54b", - "name": "aes-generated", - "providerId": "aes-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "52ea1c5d-2a30-459f-b66a-249f298b32f8", - "name": "hmac-generated", - "providerId": "hmac-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ], - "algorithm": [ - "HS256" - ] - } - } - ] - }, - "internationalizationEnabled": false, - "supportedLocales": [], - "authenticationFlows": [ - { - "id": "b35b726e-c1cc-4a31-8670-8c858c088498", - "alias": "Handle Existing Account", - "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-confirm-link", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "REQUIRED", - "priority": 20, - "flowAlias": "Handle Existing Account - Alternatives - 0", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "b7cb4b8c-0064-4c6b-95ee-d7f50011bae7", - "alias": "Handle Existing Account - Alternatives - 0", - "description": "Subflow of Handle Existing Account with alternative executions", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-email-verification", - "requirement": "ALTERNATIVE", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 20, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "2576bf21-a516-4e22-8ed8-8a1a3d35c06a", - "alias": "Verify Existing Account by Re-authentication", - "description": "Reauthentication of existing account", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-username-password-form", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "CONDITIONAL", - "priority": 20, - "flowAlias": "Verify Existing Account by Re-authentication - auth-otp-form - Conditional", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "867b0355-c2b0-4f4e-b535-09406e2bc086", - "alias": "Verify Existing Account by Re-authentication - auth-otp-form - Conditional", - "description": "Flow to determine if the auth-otp-form authenticator should be used or not.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-otp-form", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "52e45a6a-292f-4a34-9c02-7f97d9997a9c", - "alias": "browser", - "description": "browser based authentication", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-cookie", - "requirement": "ALTERNATIVE", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-spnego", - "requirement": "DISABLED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "identity-provider-redirector", - "requirement": "ALTERNATIVE", - "priority": 25, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "forms", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "ef818d24-fb06-418a-a093-16239068cb58", - "alias": "clients", - "description": "Base authentication for clients", - "providerId": "client-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "client-secret", - "requirement": "ALTERNATIVE", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "client-jwt", - "requirement": "ALTERNATIVE", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "client-secret-jwt", - "requirement": "ALTERNATIVE", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "client-x509", - "requirement": "ALTERNATIVE", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "f7864004-be4b-40f2-8534-454981f09f98", - "alias": "direct grant", - "description": "OpenID Connect Resource Owner Grant", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "direct-grant-validate-username", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "direct-grant-validate-password", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "CONDITIONAL", - "priority": 30, - "flowAlias": "direct grant - direct-grant-validate-otp - Conditional", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "233225f2-78b0-4756-9568-a775ea7cc975", - "alias": "direct grant - direct-grant-validate-otp - Conditional", - "description": "Flow to determine if the direct-grant-validate-otp authenticator should be used or not.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "direct-grant-validate-otp", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "2787939c-3312-4d56-9d61-22a71947e154", - "alias": "docker auth", - "description": "Used by Docker clients to authenticate against the IDP", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "docker-http-basic-authenticator", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "c80ca473-6e65-4140-a9d1-035414546bfb", - "alias": "first broker login", - "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "review profile config", - "authenticator": "idp-review-profile", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "REQUIRED", - "priority": 20, - "flowAlias": "first broker login - Alternatives - 0", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "700a71e1-f176-432e-9e70-ccb06d539730", - "alias": "first broker login - Alternatives - 0", - "description": "Subflow of first broker login with alternative executions", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "requirement": "ALTERNATIVE", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "ALTERNATIVE", - "priority": 20, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "13cd2ee9-8ebb-4651-8a9d-535d4020d889", - "alias": "forms", - "description": "Username, password, otp and other auth forms.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-username-password-form", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "CONDITIONAL", - "priority": 20, - "flowAlias": "forms - auth-otp-form - Conditional", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "80067ebf-72b9-4ba5-abc3-161dfdd53938", - "alias": "forms - auth-otp-form - Conditional", - "description": "Flow to determine if the auth-otp-form authenticator should be used or not.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-otp-form", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "269354b1-7dd7-46ff-8a69-084cd2c7be80", - "alias": "http challenge", - "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "no-cookie-redirect", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "basic-auth", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "basic-auth-otp", - "requirement": "DISABLED", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-spnego", - "requirement": "DISABLED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "c5fa64a0-e784-490f-8879-0e8a209e3636", - "alias": "registration", - "description": "registration flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-page-form", - "requirement": "REQUIRED", - "priority": 10, - "flowAlias": "registration form", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "bc48f897-4d16-49a8-be70-183c7867e20a", - "alias": "registration form", - "description": "registration form", - "providerId": "form-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-user-creation", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "registration-profile-action", - "requirement": "REQUIRED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "registration-password-action", - "requirement": "REQUIRED", - "priority": 50, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "registration-recaptcha-action", - "requirement": "DISABLED", - "priority": 60, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "fddaba41-87b1-40d1-b147-f062c38e39ad", - "alias": "reset credentials", - "description": "Reset credentials for a user if they forgot their password or something", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "reset-credentials-choose-user", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "reset-credential-email", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "reset-password", - "requirement": "REQUIRED", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "requirement": "CONDITIONAL", - "priority": 40, - "flowAlias": "reset credentials - reset-otp - Conditional", - "userSetupAllowed": false, - "autheticatorFlow": true - } - ] - }, - { - "id": "6b9fa295-1eb4-48b0-a286-b17ebd6be7e1", - "alias": "reset credentials - reset-otp - Conditional", - "description": "Flow to determine if the reset-otp authenticator should be used or not.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "reset-otp", - "requirement": "REQUIRED", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "id": "c890d4c4-e4e2-4618-b69d-8d30f8278965", - "alias": "saml ecp", - "description": "SAML ECP Profile Authentication Flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "http-basic-authenticator", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - } - ], - "authenticatorConfig": [ - { - "id": "2b02fbe4-e05e-4238-bb0e-04da7d4efd4e", - "alias": "create unique user config", - "config": { - "require.password.update.after.registration": "false" - } - }, - { - "id": "07dd933b-ce95-4a7c-bd81-3efa24f9558c", - "alias": "review profile config", - "config": { - "update.profile.on.first.login": "missing" - } - } - ], - "requiredActions": [ - { - "alias": "CONFIGURE_TOTP", - "name": "Configure OTP", - "providerId": "CONFIGURE_TOTP", - "enabled": true, - "defaultAction": false, - "priority": 10, - "config": {} - }, - { - "alias": "terms_and_conditions", - "name": "Terms and Conditions", - "providerId": "terms_and_conditions", - "enabled": false, - "defaultAction": false, - "priority": 20, - "config": {} - }, - { - "alias": "UPDATE_PASSWORD", - "name": "Update Password", - "providerId": "UPDATE_PASSWORD", - "enabled": true, - "defaultAction": false, - "priority": 30, - "config": {} - }, - { - "alias": "UPDATE_PROFILE", - "name": "Update Profile", - "providerId": "UPDATE_PROFILE", - "enabled": true, - "defaultAction": false, - "priority": 40, - "config": {} - }, - { - "alias": "VERIFY_EMAIL", - "name": "Verify Email", - "providerId": "VERIFY_EMAIL", - "enabled": true, - "defaultAction": false, - "priority": 50, - "config": {} - }, - { - "alias": "update_user_locale", - "name": "Update User Locale", - "providerId": "update_user_locale", - "enabled": true, - "defaultAction": false, - "priority": 1000, - "config": {} - } - ], - "browserFlow": "browser", - "registrationFlow": "registration", - "directGrantFlow": "direct grant", - "resetCredentialsFlow": "reset credentials", - "clientAuthenticationFlow": "clients", - "dockerAuthenticationFlow": "docker auth", - "attributes": { - "clientOfflineSessionMaxLifespan": "0", - "clientSessionIdleTimeout": "0", - "clientSessionMaxLifespan": "0", - "clientOfflineSessionIdleTimeout": "0" - }, - "keycloakVersion": "11.0.2", - "userManagedAccessAllowed": false -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml index 520646cc7d..004e7fa302 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -4,13 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 gateway-2 - spring-cloud-gateway + gateway-2 jar - com.baeldung.spring.cloud - spring-cloud-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../../parent-boot-2 @@ -44,107 +45,36 @@ org.springframework.cloud spring-cloud-starter-gateway - - - org.springframework.cloud - spring-cloud-starter-circuitbreaker-reactor-resilience4j - - - - org.springframework.boot - spring-boot-starter-data-redis-reactive - - - - it.ozimov - embedded-redis - ${redis.version} - test - - - org.hibernate - hibernate-validator-cdi - ${hibernate-validator.version} - - - javax.validation - validation-api - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-devtools - - - - org.springframework.boot - spring-boot-starter-oauth2-resource-server - - - org.springframework.boot - spring-boot-starter-oauth2-client - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - - - gateway-url-rewrite - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.springcloudgateway.rewrite.URLRewriteGatewayApplication - -Dspring.profiles.active=url-rewrite - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - 6.0.2.Final - 0.7.2 - 9.19 - + 2021.0.3 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java deleted file mode 100644 index fae25bb7cc..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersGatewayApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.PropertySource; - -@SpringBootApplication -@PropertySource("classpath:customfilters-global-application.properties") -public class CustomFiltersGatewayApplication { - - public static void main(String[] args) { - SpringApplication.run(CustomFiltersGatewayApplication.class, args); - } - -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java deleted file mode 100644 index 0589d8c321..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/config/WebClientConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.function.client.WebClient; - -@Configuration -public class WebClientConfig { - - @Bean - WebClient client() { - return WebClient.builder() - .build(); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java deleted file mode 100644 index f53b0a3c93..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ChainRequestGatewayFilterFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale.LanguageRange; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; - -import reactor.core.publisher.Mono; - -@Component -public class ChainRequestGatewayFilterFactory extends AbstractGatewayFilterFactory { - - final Logger logger = LoggerFactory.getLogger(ChainRequestGatewayFilterFactory.class); - - private final WebClient client; - - public ChainRequestGatewayFilterFactory(WebClient client) { - super(Config.class); - this.client = client; - } - - @Override - public List shortcutFieldOrder() { - return Arrays.asList("languageServiceEndpoint", "defaultLanguage"); - } - - @Override - public GatewayFilter apply(Config config) { - return (exchange, chain) -> { - return client.get() - .uri(config.getLanguageServiceEndpoint()) - .exchange() - .flatMap(response -> { - return (response.statusCode() - .is2xxSuccessful()) ? response.bodyToMono(String.class) : Mono.just(config.getDefaultLanguage()); - }) - .map(LanguageRange::parse) - .map(range -> { - exchange.getRequest() - .mutate() - .headers(h -> h.setAcceptLanguage(range)); - - String allOutgoingRequestLanguages = exchange.getRequest() - .getHeaders() - .getAcceptLanguage() - .stream() - .map(r -> r.getRange()) - .collect(Collectors.joining(",")); - - logger.info("Chain Request output - Request contains Accept-Language header: " + allOutgoingRequestLanguages); - - return exchange; - }) - .flatMap(chain::filter); - - }; - } - - public static class Config { - private String languageServiceEndpoint; - private String defaultLanguage; - - public Config() { - } - - public String getLanguageServiceEndpoint() { - return languageServiceEndpoint; - } - - public void setLanguageServiceEndpoint(String languageServiceEndpoint) { - this.languageServiceEndpoint = languageServiceEndpoint; - } - - public String getDefaultLanguage() { - return defaultLanguage; - } - - public void setDefaultLanguage(String defaultLanguage) { - this.defaultLanguage = defaultLanguage; - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java deleted file mode 100644 index 900d36cc02..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/LoggingGatewayFilterFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.util.Arrays; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.stereotype.Component; - -import reactor.core.publisher.Mono; - -@Component -public class LoggingGatewayFilterFactory extends AbstractGatewayFilterFactory { - - final Logger logger = LoggerFactory.getLogger(LoggingGatewayFilterFactory.class); - - public static final String BASE_MSG = "baseMessage"; - public static final String PRE_LOGGER = "preLogger"; - public static final String POST_LOGGER = "postLogger"; - - public LoggingGatewayFilterFactory() { - super(Config.class); - } - - @Override - public List shortcutFieldOrder() { - return Arrays.asList(BASE_MSG, PRE_LOGGER, POST_LOGGER); - } - - @Override - public GatewayFilter apply(Config config) { - return new OrderedGatewayFilter((exchange, chain) -> { - if (config.isPreLogger()) - logger.info("Pre GatewayFilter logging: " + config.getBaseMessage()); - return chain.filter(exchange) - .then(Mono.fromRunnable(() -> { - if (config.isPostLogger()) - logger.info("Post GatewayFilter logging: " + config.getBaseMessage()); - })); - }, 1); - } - - public static class Config { - private String baseMessage; - private boolean preLogger; - private boolean postLogger; - - public Config() { - }; - - public Config(String baseMessage, boolean preLogger, boolean postLogger) { - super(); - this.baseMessage = baseMessage; - this.preLogger = preLogger; - this.postLogger = postLogger; - } - - public String getBaseMessage() { - return this.baseMessage; - } - - public boolean isPreLogger() { - return preLogger; - } - - public boolean isPostLogger() { - return postLogger; - } - - public void setBaseMessage(String baseMessage) { - this.baseMessage = baseMessage; - } - - public void setPreLogger(boolean preLogger) { - this.preLogger = preLogger; - } - - public void setPostLogger(boolean postLogger) { - this.postLogger = postLogger; - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java deleted file mode 100644 index 5828f35a36..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyRequestGatewayFilterFactory.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.util.UriComponentsBuilder; - -@Component -public class ModifyRequestGatewayFilterFactory extends AbstractGatewayFilterFactory { - - final Logger logger = LoggerFactory.getLogger(ModifyRequestGatewayFilterFactory.class); - - public ModifyRequestGatewayFilterFactory() { - super(Config.class); - } - - @Override - public List shortcutFieldOrder() { - return Arrays.asList("defaultLocale"); - } - - @Override - public GatewayFilter apply(Config config) { - return (exchange, chain) -> { - if (exchange.getRequest() - .getHeaders() - .getAcceptLanguage() - .isEmpty()) { - - String queryParamLocale = exchange.getRequest() - .getQueryParams() - .getFirst("locale"); - - Locale requestLocale = Optional.ofNullable(queryParamLocale) - .map(l -> Locale.forLanguageTag(l)) - .orElse(config.getDefaultLocale()); - - exchange.getRequest() - .mutate() - .headers(h -> h.setAcceptLanguageAsLocales(Collections.singletonList(requestLocale))); - } - - String allOutgoingRequestLanguages = exchange.getRequest() - .getHeaders() - .getAcceptLanguage() - .stream() - .map(range -> range.getRange()) - .collect(Collectors.joining(",")); - - logger.info("Modify request output - Request contains Accept-Language header: {}", allOutgoingRequestLanguages); - - ServerWebExchange modifiedExchange = exchange.mutate() - .request(originalRequest -> originalRequest.uri(UriComponentsBuilder.fromUri(exchange.getRequest() - .getURI()) - .replaceQueryParams(new LinkedMultiValueMap()) - .build() - .toUri())) - .build(); - - logger.info("Removed all query params: {}", modifiedExchange.getRequest() - .getURI()); - - return chain.filter(modifiedExchange); - }; - } - - public static class Config { - private Locale defaultLocale; - - public Config() { - } - - public Locale getDefaultLocale() { - return defaultLocale; - } - - public void setDefaultLocale(String defaultLocale) { - this.defaultLocale = Locale.forLanguageTag(defaultLocale); - }; - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java deleted file mode 100644 index f5efa69402..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ModifyResponseGatewayFilterFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.util.Optional; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.stereotype.Component; - -import reactor.core.publisher.Mono; - -@Component -public class ModifyResponseGatewayFilterFactory extends AbstractGatewayFilterFactory { - - final Logger logger = LoggerFactory.getLogger(ModifyResponseGatewayFilterFactory.class); - - public ModifyResponseGatewayFilterFactory() { - super(Config.class); - } - - @Override - public GatewayFilter apply(Config config) { - return (exchange, chain) -> { - return chain.filter(exchange) - .then(Mono.fromRunnable(() -> { - ServerHttpResponse response = exchange.getResponse(); - - Optional.ofNullable(exchange.getRequest() - .getQueryParams() - .getFirst("locale")) - .ifPresent(qp -> { - String responseContentLanguage = response.getHeaders() - .getContentLanguage() - .getLanguage(); - - response.getHeaders() - .add("Bael-Custom-Language-Header", responseContentLanguage); - logger.info("Added custom header to Response"); - }); - })); - }; - } - - public static class Config { - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java deleted file mode 100644 index dbe9a9fb4f..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactory.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -import org.reactivestreams.Publisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory; -import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; - -import reactor.core.publisher.Mono; - -@Component -public class ScrubResponseGatewayFilterFactory extends AbstractGatewayFilterFactory { - - final Logger logger = LoggerFactory.getLogger(ScrubResponseGatewayFilterFactory.class); - private ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory; - - public ScrubResponseGatewayFilterFactory(ModifyResponseBodyGatewayFilterFactory modifyResponseBodyFilterFactory) { - super(Config.class); - this.modifyResponseBodyFilterFactory = modifyResponseBodyFilterFactory; - } - - @Override - public List shortcutFieldOrder() { - return Arrays.asList("fields", "replacement"); - } - - - @Override - public GatewayFilter apply(Config config) { - - return modifyResponseBodyFilterFactory - .apply(c -> c.setRewriteFunction(JsonNode.class, JsonNode.class, new Scrubber(config))); - } - - public static class Config { - - private String fields; - private String replacement; - - - public String getFields() { - return fields; - } - public void setFields(String fields) { - this.fields = fields; - } - public String getReplacement() { - return replacement; - } - public void setReplacement(String replacement) { - this.replacement = replacement; - } - } - - - public static class Scrubber implements RewriteFunction { - private final Pattern fields; - private final String replacement; - - public Scrubber(Config config) { - this.fields = Pattern.compile(config.getFields()); - this.replacement = config.getReplacement(); - } - - @Override - public Publisher apply(ServerWebExchange t, JsonNode u) { - return Mono.just(scrubRecursively(u)); - } - - private JsonNode scrubRecursively(JsonNode u) { - if ( !u.isContainerNode()) { - return u; - } - - if ( u.isObject()) { - ObjectNode node = (ObjectNode)u; - node.fields().forEachRemaining((f) -> { - if ( fields.matcher(f.getKey()).matches() && f.getValue().isTextual()) { - f.setValue(TextNode.valueOf(replacement)); - } - else { - f.setValue(scrubRecursively(f.getValue())); - } - }); - } - else if ( u.isArray()) { - ArrayNode array = (ArrayNode)u; - for ( int i = 0 ; i < array.size() ; i++ ) { - array.set(i, scrubRecursively(array.get(i))); - } - } - - return u; - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java deleted file mode 100644 index 687f3fe685..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/FirstPreLastPostGlobalFilter.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -import reactor.core.publisher.Mono; - -@Component -public class FirstPreLastPostGlobalFilter implements GlobalFilter, Ordered { - - final Logger logger = LoggerFactory.getLogger(FirstPreLastPostGlobalFilter.class); - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - logger.info("First Pre Global Filter"); - return chain.filter(exchange) - .then(Mono.fromRunnable(() -> { - logger.info("Last Post Global Filter"); - })); - } - - @Override - public int getOrder() { - return -1; - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java deleted file mode 100644 index 4bf6453355..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFilterProperties.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("logging.global") -public class LoggingGlobalFilterProperties { - - private boolean enabled; - private boolean requestHeaders; - private boolean requestBody; - private boolean responseHeaders; - private boolean responseBody; - - public boolean isEnabled() { - return enabled; - } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - public boolean isRequestHeaders() { - return requestHeaders; - } - public void setRequestHeaders(boolean requestHeaders) { - this.requestHeaders = requestHeaders; - } - public boolean isRequestBody() { - return requestBody; - } - public void setRequestBody(boolean requestBody) { - this.requestBody = requestBody; - } - public boolean isResponseHeaders() { - return responseHeaders; - } - public void setResponseHeaders(boolean responseHeaders) { - this.responseHeaders = responseHeaders; - } - public boolean isResponseBody() { - return responseBody; - } - public void setResponseBody(boolean responseBody) { - this.responseBody = responseBody; - } - - - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java deleted file mode 100644 index 2dead8da3b..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalFiltersConfigurations.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import reactor.core.publisher.Mono; - -@Configuration -public class LoggingGlobalFiltersConfigurations { - - final Logger logger = LoggerFactory.getLogger(LoggingGlobalFiltersConfigurations.class); - - @Bean - public GlobalFilter postGlobalFilter() { - return (exchange, chain) -> { - return chain.filter(exchange) - .then(Mono.fromRunnable(() -> { - logger.info("Global Post Filter executed"); - })); - }; - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java deleted file mode 100644 index 2bacf033db..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/global/LoggingGlobalPreFilter.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.global; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -import reactor.core.publisher.Mono; - -@Component -public class LoggingGlobalPreFilter implements GlobalFilter { - - final Logger logger = LoggerFactory.getLogger(LoggingGlobalPreFilter.class); - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - logger.info("Global Pre Filter executed"); - return chain.filter(exchange); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java deleted file mode 100644 index 17d4827d93..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/routes/ServiceRouteConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.routes; - -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; - -import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory; -import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.LoggingGatewayFilterFactory.Config; - -/** - * Note: We want to keep this as an example of configuring a Route with a custom filter - * - * This corresponds with the properties configuration we have - */ -// @Configuration -public class ServiceRouteConfiguration { - - @Bean - public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) { - - return builder.routes() - .route("service_route_java_config", r -> r.path("/service/**") - .filters(f -> f.rewritePath("/service(?/?.*)", "$\\{segment}") - .filter(loggingFactory.apply(new Config("My Custom Message", true, true)))) - .uri("http://localhost:8081")) - .build(); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java deleted file mode 100644 index b65d0efbd6..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.secondservice; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.PropertySource; - -@SpringBootApplication -@PropertySource("classpath:secondservice-application.properties") -public class SecondServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(SecondServiceApplication.class, args); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java deleted file mode 100644 index 1ac44ba6b1..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/secondservice/web/SecondServiceRestController.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.secondservice.web; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import reactor.core.publisher.Mono; - -@RestController -public class SecondServiceRestController { - - @GetMapping("/resource/language") - public Mono> getResource() { - return Mono.just(ResponseEntity.ok() - .body("es")); - - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java deleted file mode 100644 index 1e2ffb63c2..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/ServiceApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.service; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.PropertySource; - -@SpringBootApplication -@PropertySource("classpath:service-application.properties") -public class ServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(ServiceApplication.class, args); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java deleted file mode 100644 index 3ca09f6853..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/customfilters/service/web/ServiceRestController.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.service.web; - -import java.util.Locale; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import reactor.core.publisher.Mono; - -@RestController -public class ServiceRestController { - - @GetMapping("/resource") - public Mono> getResource() { - return Mono.just(ResponseEntity.ok() - .header(HttpHeaders.CONTENT_LANGUAGE, Locale.ENGLISH.getLanguage()) - .body("Service Resource")); - - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java deleted file mode 100644 index 46541b4826..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplication.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * - */ -package com.baeldung.springcloudgateway.rewrite; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.gateway.filter.GatewayFilter; - -import reactor.core.publisher.Mono; - -/** - * @author Baeldung - * - */ -@SpringBootApplication -public class URLRewriteGatewayApplication { - - public static void main(String[] args) { - new SpringApplicationBuilder(URLRewriteGatewayApplication.class) - .profiles("url-rewrite") - .run(args); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java deleted file mode 100644 index 29d40d7021..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/rewrite/routes/DynamicRewriteRoute.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.springcloudgateway.rewrite.routes; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.http.server.reactive.ServerHttpRequest; - -import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; -import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl; - -import java.util.Random; - -@Configuration -@Profile("url-rewrite") -public class DynamicRewriteRoute { - - @Value("${rewrite.backend.uri}") - private String backendUri; - private static Random rnd = new Random(); - - @Bean - public RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) { - return builder.routes() - .route("dynamicRewrite", r -> - r.path("/v2/zip/**") - .filters(f -> f.filter((exchange, chain) -> { - ServerHttpRequest req = exchange.getRequest(); - addOriginalRequestUrl(exchange, req.getURI()); - String path = req.getURI().getRawPath(); - String newPath = path.replaceAll( - "/v2/zip/(?.*)", - "/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000))); - ServerHttpRequest request = req.mutate().path(newPath).build(); - exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI()); - return chain.filter(exchange.mutate().request(request).build()); - })) - .uri(backendUri)) - .build(); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java deleted file mode 100644 index 9e212cc4bf..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/WebFilterGatewayApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.springcloudgateway.webfilters; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; - -@SpringBootApplication -public class WebFilterGatewayApplication { - - public static void main(String[] args) { - new SpringApplicationBuilder(WebFilterGatewayApplication.class) - .profiles("url-rewrite") - .run(args); - } - -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java deleted file mode 100644 index 7b6188b66a..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/ModifyBodyRouteConfig.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.springcloudgateway.webfilters.config; - -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; - -import reactor.core.publisher.Mono; - -@Configuration -public class ModifyBodyRouteConfig { - - @Bean - public RouteLocator routes(RouteLocatorBuilder builder) { - return builder.routes() - .route("modify_request_body", r -> r.path("/post") - .filters(f -> f.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, - (exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri("https://httpbin.org")) - .build(); - } - - @Bean - public RouteLocator responseRoutes(RouteLocatorBuilder builder) { - return builder.routes() - .route("modify_response_body", r -> r.path("/put/**") - .filters(f -> f.modifyResponseBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE, - (exchange, s) -> Mono.just(new Hello("New Body")))).uri("https://httpbin.org")) - .build(); - } - - static class Hello { - String message; - - public Hello() { } - - public Hello(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java deleted file mode 100644 index f80a742fa6..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/webfilters/config/RequestRateLimiterResolverConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.springcloudgateway.webfilters.config; - -import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import reactor.core.publisher.Mono; - -@Configuration -public class RequestRateLimiterResolverConfig { - - @Bean - KeyResolver userKeyResolver() { - return exchange -> Mono.just("1"); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml deleted file mode 100644 index 40a52ded0f..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-nosecurity.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Enable this profile to disable security -spring: - autoconfigure: - exclude: - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration - - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml deleted file mode 100644 index da7dfea0a7..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-scrub.yml +++ /dev/null @@ -1,12 +0,0 @@ -spring: - cloud: - gateway: - routes: - - id: rewrite_with_scrub - uri: ${rewrite.backend.uri:http://example.com} - predicates: - - Path=/v1/customer/** - filters: - - RewritePath=/v1/customer/(?.*),/api/$\{segment} - - ScrubResponse=ssn,*** - \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml deleted file mode 100644 index b2656151db..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-url-rewrite.yml +++ /dev/null @@ -1,11 +0,0 @@ -spring: - cloud: - gateway: - routes: - - id: rewrite_v1 - uri: ${rewrite.backend.uri:http://example.com} - predicates: - - Path=/v1/customer/** - filters: - - RewritePath=/v1/customer/(?.*),/api/$\{segment} - \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml deleted file mode 100644 index 3348cbbba0..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-webfilters.yml +++ /dev/null @@ -1,102 +0,0 @@ -logging: - level: - org.springframework.cloud.gateway: INFO - reactor.netty.http.client: INFO - -spring: - redis: - host: localhost - port: 6379 - cloud: - gateway: - routes: - - id: request_header_route - uri: https://httpbin.org - predicates: - - Path=/get/** - filters: - - AddRequestHeader=My-Header-Good,Good - - AddRequestHeader=My-Header-Remove,Remove - - AddRequestParameter=var, good - - AddRequestParameter=var2, remove - - MapRequestHeader=My-Header-Good, My-Header-Bad - - MapRequestHeader=My-Header-Set, My-Header-Bad - - SetRequestHeader=My-Header-Set, Set - - RemoveRequestHeader=My-Header-Remove - - RemoveRequestParameter=var2 - - PreserveHostHeader - - - id: response_header_route - uri: https://httpbin.org - predicates: - - Path=/header/post/** - filters: - - AddResponseHeader=My-Header-Good,Good - - AddResponseHeader=My-Header-Set,Good - - AddResponseHeader=My-Header-Rewrite, password=12345678 - - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin - - AddResponseHeader=My-Header-Remove,Remove - - SetResponseHeader=My-Header-Set, Set - - RemoveResponseHeader=My-Header-Remove - - RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=*** - - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, , - - StripPrefix=1 - - - id: path_route - uri: https://httpbin.org - predicates: - - Path=/new/post/** - filters: - - RewritePath=/new(?/?.*), $\{segment} - - SetPath=/post - - - id: redirect_route - uri: https://httpbin.org - predicates: - - Path=/fake/post/** - filters: - - RedirectTo=302, https://httpbin.org - - - id: status_route - uri: https://httpbin.org - predicates: - - Path=/delete/** - filters: - - SetStatus=401 - - - id: size_route - uri: https://httpbin.org - predicates: - - Path=/anything - filters: - - name: RequestSize - args: - maxSize: 5000000 - - - id: retry_test - uri: https://httpbin.org - predicates: - - Path=/status/502 - filters: - - name: Retry - args: - retries: 3 - statuses: BAD_GATEWAY - methods: GET,POST - backoff: - firstBackoff: 10ms - maxBackoff: 50ms - factor: 2 - basedOnPreviousValue: false - - - id: request_rate_limiter - uri: https://httpbin.org - predicates: - - Path=/redis/get/** - filters: - - StripPrefix=1 - - name: RequestRateLimiter - args: - redis-rate-limiter.replenishRate: 10 - redis-rate-limiter.burstCapacity: 5 - key-resolver: "#{@userKeyResolver}" \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties deleted file mode 100644 index 08421a0653..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/customfilters-global-application.properties +++ /dev/null @@ -1,19 +0,0 @@ -spring.cloud.gateway.routes[0].id=service_route -spring.cloud.gateway.routes[0].uri=http://localhost:8081 -spring.cloud.gateway.routes[0].predicates[0]=Path=/service/** -spring.cloud.gateway.routes[0].filters[0]=RewritePath=/service(?/?.*), $\{segment} -spring.cloud.gateway.routes[0].filters[1]=Logging=My Custom Message, true, true -# Or, as an alternative: -#spring.cloud.gateway.routes[0].filters[1].name=Logging -#spring.cloud.gateway.routes[0].filters[1].args[baseMessage]=My Custom Message -#spring.cloud.gateway.routes[0].filters[1].args[preLogger]=true -#spring.cloud.gateway.routes[0].filters[1].args[postLogger]=true - -spring.cloud.gateway.routes[0].filters[2]=ModifyResponse -spring.cloud.gateway.routes[0].filters[3]=ModifyRequest=en -spring.cloud.gateway.routes[0].filters[4]=ChainRequest=http://localhost:8082/resource/language, fr - -management.endpoints.web.exposure.include=* - -server.port=80 - diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties deleted file mode 100644 index 3cf12afeb9..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/secondservice-application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=8082 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties deleted file mode 100644 index 4d360de145..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/service-application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=8081 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java deleted file mode 100644 index f49f8c68b6..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/CustomFiltersLiveTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.assertj.core.api.Condition; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; - -import com.baeldung.springcloudgateway.customfilters.gatewayapp.utils.LoggerListAppender; - -import ch.qos.logback.classic.spi.ILoggingEvent; - -/** - * This test requires: - * * the service in com.baeldung.service running - * * the 'second service' in com.baeldung.secondservice running - * - */ -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class CustomFiltersLiveTest { - - @LocalServerPort - String port; - - @Autowired - private WebTestClient client; - - @BeforeEach - public void clearLogList() { - LoggerListAppender.clearEventList(); - client = WebTestClient.bindToServer() - .baseUrl("http://localhost:" + port) - .build(); - } - - @Test - public void whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { - ResponseSpec response = client.get() - .uri("/service/resource") - .exchange(); - - response.expectStatus() - .isOk() - .expectHeader() - .doesNotExist("Bael-Custom-Language-Header") - .expectBody(String.class) - .isEqualTo("Service Resource"); - - assertThat(LoggerListAppender.getEvents()) - // Global Pre Filter - .haveAtLeastOne(eventContains("Global Pre Filter executed")) - // Global Post Filter - .haveAtLeastOne(eventContains("Global Post Filter executed")) - // Global Pre and Post Filter - .haveAtLeastOne(eventContains("First Pre Global Filter")) - .haveAtLeastOne(eventContains("Last Post Global Filter")) - // Logging Filter Factory - .haveAtLeastOne(eventContains("Pre GatewayFilter logging: My Custom Message")) - .haveAtLeastOne(eventContains("Post GatewayFilter logging: My Custom Message")) - // Modify Request - .haveAtLeastOne(eventContains("Modify request output - Request contains Accept-Language header:")) - .haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale")) - // Modify Response - .areNot(eventContains("Added custom header to Response")) - // Chain Request - .haveAtLeastOne(eventContains("Chain Request output - Request contains Accept-Language header:")); - } - - @Test - public void givenRequestWithLocaleQueryParam_whenCallServiceThroughGateway_thenAllConfiguredFiltersGetExecuted() { - ResponseSpec response = client.get() - .uri("/service/resource?locale=en") - .exchange(); - - response.expectStatus() - .isOk() - .expectHeader() - .exists("Bael-Custom-Language-Header") - .expectBody(String.class) - .isEqualTo("Service Resource"); - - assertThat(LoggerListAppender.getEvents()) - // Modify Response - .haveAtLeastOne(eventContains("Added custom header to Response")) - .haveAtLeastOne(eventContainsExcept("Removed all query params: ", "locale")); - } - - /** - * This condition will be successful if the event contains a substring - */ - private Condition eventContains(String substring) { - return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() - .contains(substring))), String.format("entry with message '%s'", substring)); - } - - /** - * This condition will be successful if the event contains a substring, but not another one - */ - private Condition eventContainsExcept(String substring, String except) { - return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() - .contains(substring) - && !entry.getFormattedMessage() - .contains(except))), - String.format("entry with message '%s'", substring)); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java deleted file mode 100644 index 667aabaddc..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterFactoryUnitTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Config; -import com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories.ScrubResponseGatewayFilterFactory.Scrubber; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import reactor.core.publisher.Mono; - -class ScrubResponseGatewayFilterFactoryUnitTest { - - private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" - + " \"name\" : \"John Doe\",\r\n" - + " \"ssn\" : \"123-45-9999\",\r\n" - + " \"account\" : \"9999888877770000\"\r\n" - + "}"; - - - @Test - void givenJsonWithFieldsToScrub_whenApply_thenScrubFields() throws Exception{ - - JsonFactory jf = new JsonFactory(new ObjectMapper()); - JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); - JsonNode root = parser.readValueAsTree(); - - Config config = new Config(); - config.setFields("ssn|account"); - config.setReplacement("*"); - Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); - - JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); - assertNotNull(scrubbed); - assertEquals("*", scrubbed.get("ssn").asText()); - } - - @Test - void givenJsonWithoutFieldsToScrub_whenApply_theBodUnchanged() throws Exception{ - - JsonFactory jf = new JsonFactory(new ObjectMapper()); - JsonParser parser = jf.createParser(JSON_WITH_FIELDS_TO_SCRUB); - JsonNode root = parser.readValueAsTree(); - - Config config = new Config(); - config.setFields("xxxx"); - config.setReplacement("*"); - Scrubber scrubber = new ScrubResponseGatewayFilterFactory.Scrubber(config); - - JsonNode scrubbed = Mono.from(scrubber.apply(null, root)).block(); - assertNotNull(scrubbed); - assertNotEquals("*", scrubbed.get("ssn").asText()); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java deleted file mode 100644 index 8906af774e..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/filters/factories/ScrubResponseGatewayFilterLiveTest.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.filters.factories; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Collections; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; -import org.springframework.http.MediaType; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.test.web.reactive.server.WebTestClient; - -import com.sun.net.httpserver.HttpServer; - -import reactor.netty.http.client.HttpClient; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class ScrubResponseGatewayFilterLiveTest { - - private static Logger log = LoggerFactory.getLogger(ScrubResponseGatewayFilterLiveTest.class); - - private static final String JSON_WITH_FIELDS_TO_SCRUB = "{\r\n" - + " \"name\" : \"John Doe\",\r\n" - + " \"ssn\" : \"123-45-9999\",\r\n" - + " \"account\" : \"9999888877770000\"\r\n" - + "}"; - - private static final String JSON_WITH_SCRUBBED_FIELDS = "{\r\n" - + " \"name\" : \"John Doe\",\r\n" - + " \"ssn\" : \"*\",\r\n" - + " \"account\" : \"9999888877770000\"\r\n" - + "}"; - - @LocalServerPort - String port; - - @Autowired - private WebTestClient client; - - @Autowired HttpServer server; - - @Test - public void givenRequestToScrubRoute_thenResponseScrubbed() { - - client.get() - .uri("/scrub") - .accept(MediaType.APPLICATION_JSON) - .exchange() - .expectStatus() - .is2xxSuccessful() - .expectHeader() - .contentType(MediaType.APPLICATION_JSON) - .expectBody() - .json(JSON_WITH_SCRUBBED_FIELDS); - } - - - @TestConfiguration - public static class TestRoutesConfiguration { - - - @Bean - public RouteLocator scrubSsnRoute(RouteLocatorBuilder builder, ScrubResponseGatewayFilterFactory scrubFilterFactory, SetPathGatewayFilterFactory pathFilterFactory, HttpServer server ) { - - log.info("[I92] Creating scrubSsnRoute..."); - - int mockServerPort = server.getAddress().getPort(); - ScrubResponseGatewayFilterFactory.Config config = new ScrubResponseGatewayFilterFactory.Config(); - config.setFields("ssn"); - config.setReplacement("*"); - - SetPathGatewayFilterFactory.Config pathConfig = new SetPathGatewayFilterFactory.Config(); - pathConfig.setTemplate("/customer"); - - return builder.routes() - .route("scrub_ssn", - r -> r.path("/scrub") - .filters( - f -> f - .filter(scrubFilterFactory.apply(config)) - .filter(pathFilterFactory.apply(pathConfig))) - .uri("http://localhost:" + mockServerPort )) - .build(); - } - - @Bean - public SecurityWebFilterChain testFilterChain(ServerHttpSecurity http ) { - - // @formatter:off - return http.authorizeExchange() - .anyExchange() - .permitAll() - .and() - .build(); - // @formatter:on - } - - @Bean - public HttpServer mockServer() throws IOException { - - log.info("[I48] Starting mock server..."); - - HttpServer server = HttpServer.create(new InetSocketAddress(0),0); - server.createContext("/customer", (exchange) -> { - exchange.getResponseHeaders().set("Content-Type", "application/json"); - - byte[] response = JSON_WITH_FIELDS_TO_SCRUB.getBytes("UTF-8"); - exchange.sendResponseHeaders(200,response.length); - exchange.getResponseBody().write(response); - }); - - server.setExecutor(null); - server.start(); - - log.info("[I65] Mock server started. port={}", server.getAddress().getPort()); - return server; - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java deleted file mode 100644 index f4b3d0f00d..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.secondservice; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.test.web.reactive.server.WebTestClient; - -import com.baeldung.springcloudgateway.customfilters.secondservice.web.SecondServiceRestController; - -@WebFluxTest(controllers = SecondServiceRestController.class, - excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) -public class SecondServiceIntegrationTest { - - @Autowired - private WebTestClient webClient; - - @Test - public void whenResourceLanguageEndpointCalled_thenRetrievesSpanishLanguageString() throws Exception { - this.webClient.get() - .uri("/resource/language") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .isEqualTo("es"); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java deleted file mode 100644 index eaf94c0a42..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SpringContextTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.secondservice; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(classes = SecondServiceApplication.class) -public class SpringContextTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java deleted file mode 100644 index 9990cd003c..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.service; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.http.HttpHeaders; -import org.springframework.test.web.reactive.server.WebTestClient; - -import com.baeldung.springcloudgateway.customfilters.service.web.ServiceRestController; - -@WebFluxTest(controllers = ServiceRestController.class, - excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class) -public class ServiceIntegrationTest { - - @Autowired - private WebTestClient webClient; - - @Test - public void whenResourceEndpointCalled_thenRetrievesResourceStringWithContentLanguageHeader() throws Exception { - this.webClient.get() - .uri("/resource") - .exchange() - .expectStatus() - .isOk() - .expectHeader() - .valueEquals(HttpHeaders.CONTENT_LANGUAGE, "en") - .expectBody(String.class) - .isEqualTo("Service Resource"); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java deleted file mode 100644 index 2a9b322d5e..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/service/SpringContextTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.springcloudgateway.customfilters.service; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(classes = ServiceApplication.class) -public class SpringContextTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java similarity index 88% rename from spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java rename to spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java index 8e113b417b..33855cd15d 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/customfilters/gatewayapp/utils/LoggerListAppender.java +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java @@ -1,4 +1,4 @@ -package com.baeldung.springcloudgateway.customfilters.gatewayapp.utils; +package com.baeldung.springcloudgateway.introduction; import java.util.ArrayList; import java.util.List; diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java deleted file mode 100644 index 41fe37045c..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/rewrite/URLRewriteGatewayApplicationLiveTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.baeldung.springcloudgateway.rewrite; - -import static org.junit.Assert.assertTrue; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.OutputStream; -import java.net.InetSocketAddress; - -import org.junit.AfterClass; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.web.reactive.server.WebTestClient; - -import com.sun.net.httpserver.HttpServer; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ActiveProfiles({ "nosecurity", "url-rewrite" }) -class URLRewriteGatewayApplicationLiveTest { - - // NOTE for Eclipse users: By default, Eclipse will complain about com.sun.** classes. - // To solve this issue, follow instructions available at the : - // https://stackoverflow.com/questions/13155734/eclipse-cant-recognize-com-sun-net-httpserver-httpserver-package - private static HttpServer mockServer; - private static Logger log = LoggerFactory.getLogger(URLRewriteGatewayApplicationLiveTest.class); - - // Create a running HttpServer that echoes back the request URL. - private static HttpServer startTestServer() { - - try { - log.info("[I26] Starting mock server"); - mockServer = HttpServer.create(); - mockServer.bind(new InetSocketAddress(0), 0); - mockServer.createContext("/api", (xchg) -> { - String uri = xchg.getRequestURI() - .toString(); - log.info("[I23] Backend called: uri={}", uri); - xchg.getResponseHeaders() - .add("Content-Type", "text/plain"); - xchg.sendResponseHeaders(200, 0); - OutputStream os = xchg.getResponseBody(); - os.write(uri.getBytes()); - os.flush(); - os.close(); - }); - - mockServer.start(); - InetSocketAddress localAddr = mockServer.getAddress(); - log.info("[I36] mock server started: local address={}", localAddr); - - return mockServer; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - - } - - // TIP: https://www.baeldung.com/spring-dynamicpropertysource - @DynamicPropertySource - static void registerBackendServer(DynamicPropertyRegistry registry) { - registry.add("rewrite.backend.uri", () -> { - HttpServer s = startTestServer(); - return "http://localhost:" + s.getAddress().getPort(); - }); - } - - @AfterClass - public static void stopMockBackend() throws Exception { - log.info("[I40] Shutdown mock http server"); - mockServer.stop(5); - } - - @LocalServerPort - private int localPort; - - @Test - void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { - webClient.get() - .uri("http://localhost:" + localPort + "/v1/customer/customer1") - .exchange() - .expectBody() - .consumeWith((result) -> { - String body = new String(result.getResponseBody()); - log.info("[I99] body={}", body); - assertEquals("/api/customer1", body); - }); - } - - @Test - void testWhenDslCall_thenRewriteSuccess(@Autowired WebTestClient webClient) { - webClient.get() - .uri("http://localhost:" + localPort + "/v2/zip/123456") - .exchange() - .expectBody() - .consumeWith((result) -> { - String body = new String(result.getResponseBody()); - log.info("[I99] body={}", body); - assertTrue(body.matches("/api/zip/123456-\\d{3}")); - }); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java deleted file mode 100644 index a28eb68775..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/RedisWebFilterFactoriesLiveTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.springcloudgateway.webfilters; - -import org.junit.After; -import org.junit.Before; -import org.junit.jupiter.api.RepeatedTest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; - -import redis.embedded.RedisServer; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ActiveProfiles("webfilters") -@TestConfiguration -public class RedisWebFilterFactoriesLiveTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedisWebFilterFactoriesLiveTest.class); - - private RedisServer redisServer; - - public RedisWebFilterFactoriesLiveTest() { - } - - @Before - public void postConstruct() { - this.redisServer = new RedisServer(6379); - redisServer.start(); - } - - @LocalServerPort - String port; - - @Autowired - private TestRestTemplate restTemplate; - - @Autowired - TestRestTemplate template; - - @RepeatedTest(25) - public void whenCallRedisGetThroughGateway_thenOKStatusOrIsReceived() { - String url = "http://localhost:" + port + "/redis/get"; - - ResponseEntity r = restTemplate.getForEntity(url, String.class); - // assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - - LOGGER.info("Received: status->{}, reason->{}, remaining->{}", - r.getStatusCodeValue(), r.getStatusCode().getReasonPhrase(), - r.getHeaders().get("X-RateLimit-Remaining")); - } - - @After - public void preDestroy() { - redisServer.stop(); - } - -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java deleted file mode 100644 index 67e00a42fc..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/webfilters/WebFilterFactoriesLiveTest.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.baeldung.springcloudgateway.webfilters; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.assertj.core.api.Condition; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ActiveProfiles("webfilters") -public class WebFilterFactoriesLiveTest { - - @LocalServerPort - String port; - - @Autowired - private WebTestClient client; - - @Autowired - private TestRestTemplate restTemplate; - - @BeforeEach - public void configureClient() { - client = WebTestClient.bindToServer() - .baseUrl("http://localhost:" + port) - .build(); - } - - @Test - public void whenCallGetThroughGateway_thenAllHTTPRequestHeadersParametersAreSet() throws JSONException { - String url = "http://localhost:" + port + "/get"; - ResponseEntity response = restTemplate.getForEntity(url, String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - - JSONObject json = new JSONObject(response.getBody()); - JSONObject headers = json.getJSONObject("headers"); - assertThat(headers.getString("My-Header-Good")).isEqualTo("Good"); - assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good"); - assertThat(headers.getString("My-Header-Set")).isEqualTo("Set"); - assertTrue(headers.isNull("My-Header-Remove")); - JSONObject vars = json.getJSONObject("args"); - assertThat(vars.getString("var")).isEqualTo("good"); - } - - @Test - public void whenCallHeaderPostThroughGateway_thenAllHTTPResponseHeadersAreSet() { - ResponseSpec response = client.post() - .uri("/header/post") - .exchange(); - - response.expectStatus() - .isOk() - .expectHeader() - .valueEquals("My-Header-Rewrite", "password=***") - .expectHeader() - .valueEquals("My-Header-Set", "Set") - .expectHeader() - .valueEquals("My-Header-Good", "Good") - .expectHeader() - .doesNotExist("My-Header-Remove"); - } - - @Test - public void whenCallPostThroughGateway_thenBodyIsRetrieved() throws JSONException { - String url = "http://localhost:" + port + "/post"; - - HttpEntity entity = new HttpEntity<>("content", new HttpHeaders()); - - ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - - JSONObject json = new JSONObject(response.getBody()); - JSONObject data = json.getJSONObject("json"); - assertThat(data.getString("message")).isEqualTo("CONTENT"); - } - - @Test - public void whenCallPutThroughGateway_thenBodyIsRetrieved() throws JSONException { - String url = "http://localhost:" + port + "/put"; - - HttpEntity entity = new HttpEntity<>("CONTENT", new HttpHeaders()); - - ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - - JSONObject json = new JSONObject(response.getBody()); - assertThat(json.getString("message")).isEqualTo("New Body"); - } - - @Test - public void whenCallDeleteThroughGateway_thenIsUnauthorizedCodeIsSet() { - ResponseSpec response = client.delete() - .uri("/delete") - .exchange(); - - response.expectStatus() - .isUnauthorized(); - } - - @Test - public void whenCallFakePostThroughGateway_thenIsUnauthorizedCodeIsSet() { - ResponseSpec response = client.post() - .uri("/fake/post") - .exchange(); - - response.expectStatus() - .is3xxRedirection(); - } - - @Test - public void whenCallStatus504ThroughGateway_thenCircuitBreakerIsExecuted() throws JSONException { - String url = "http://localhost:" + port + "/status/504"; - ResponseEntity response = restTemplate.getForEntity(url, String.class); - - JSONObject json = new JSONObject(response.getBody()); - assertThat(json.getString("url")).contains("anything"); - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json deleted file mode 100644 index ac920a271b..0000000000 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/postman/OAuth_Gateway.postman_collection.json +++ /dev/null @@ -1,203 +0,0 @@ -{ - "info": { - "_postman_id": "b3d00e23-c2cd-40ce-a90b-673efb25e5c0", - "name": "Baeldung - OAuth", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Token", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var jsonData = pm.response.json();\r", - "pm.environment.set(\"access_token\", jsonData.access_token);\r", - "pm.environment.set(\"refresh_token\", jsonData.refresh_token);\r", - "pm.environment.set(\"backend_token\", \"Bearer \" + jsonData.access_token);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "client_id", - "value": "{{client_id}}", - "type": "text" - }, - { - "key": "client_secret", - "value": "{{client_secret}}", - "type": "text" - }, - { - "key": "grant_type", - "value": "password", - "type": "text" - }, - { - "key": "scope", - "value": "email roles profile", - "type": "text" - }, - { - "key": "username", - "value": "maxwell.smart", - "type": "text" - }, - { - "key": "password", - "value": "1234", - "type": "text" - } - ] - }, - "url": { - "raw": "{{keycloack_base}}/token", - "host": [ - "{{keycloack_base}}" - ], - "path": [ - "token" - ] - } - }, - "response": [] - }, - { - "name": "Quote", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "accept": true - } - }, - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{access_token}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json", - "type": "text" - } - ], - "url": { - "raw": "http://localhost:8085/quotes/:symbol", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8085", - "path": [ - "quotes", - ":symbol" - ], - "variable": [ - { - "key": "symbol", - "value": "IBM" - } - ] - } - }, - "response": [] - }, - { - "name": "Quote via Gateway", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "accept": true - } - }, - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{access_token}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json", - "type": "text" - } - ], - "url": { - "raw": "http://localhost:8086/quotes/:symbol", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8086", - "path": [ - "quotes", - ":symbol" - ], - "variable": [ - { - "key": "symbol", - "value": "IBM" - } - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "keycloack_base", - "value": "http://localhost:8083/auth/realms/baeldung/protocol/openid-connect" - }, - { - "key": "client_id", - "value": "quotes-client" - }, - { - "key": "client_secret", - "value": "56be94c8-b20a-4374-899c-e39cb022d3f8" - } - ] -} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml index 6980d119b1..90c8f570aa 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml @@ -1,7 +1,7 @@ + class="com.baeldung.springcloudgateway.introduction.LoggerListAppender"> From ac054b44bba5567e2e1d581d9395cb9817b9f4eb Mon Sep 17 00:00:00 2001 From: Anastasios Ioannidis Date: Thu, 28 Sep 2023 11:49:20 +0300 Subject: [PATCH 047/135] JAVA-13321 Clean up --- .../spring-cloud-bootstrap/gateway-2/pom.xml | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml index 004e7fa302..3d64edc338 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -47,32 +47,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - 2021.0.3 From a50bdf68166803c5ec7be67a7a34abf28742459b Mon Sep 17 00:00:00 2001 From: timis1 Date: Fri, 29 Sep 2023 09:14:20 +0300 Subject: [PATCH 048/135] JAVA-25350 Potential issue in "Sorting Java Map in Descending Order" article --- .../objecttomap/ObjectToMapUnitTest.java | 76 ----------- .../objecttomap/ObjectToMapUnitTest.java | 128 ++++++++++++++++++ 2 files changed, 128 insertions(+), 76 deletions(-) delete mode 100644 core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java create mode 100644 core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java diff --git a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java deleted file mode 100644 index 52c2fb2bea..0000000000 --- a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package java.com.baeldung.objecttomap; -import com.google.gson.Gson; -import org.junit.Assert; -import org.junit.Test; -import wiremock.com.fasterxml.jackson.core.type.TypeReference; -import wiremock.com.fasterxml.jackson.databind.ObjectMapper; -import wiremock.com.google.common.reflect.TypeToken; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - -public class ObjectToMapUnitTest { - Employee employee = new Employee("John", 3000.0); - - @Test - public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { - Map map = convertUsingReflection(employee); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private Map convertUsingReflection(Object object) throws IllegalAccessException { - Map map = new HashMap<>(); - Field[] fields = object.getClass().getDeclaredFields(); - - for (Field field : fields) { - field.setAccessible(true); - map.put(field.getName(), field.get(object)); - } - - return map; - } - - @Test - public void givenJavaObject_whenUsingJackson_thenConvertToMap() { - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.convertValue(employee, new TypeReference>() {}); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - @Test - public void givenJavaObject_whenUsingGson_thenConvertToMap() { - Gson gson = new Gson(); - String json = gson.toJson(employee); - Map map = gson.fromJson(json, new TypeToken>() {}.getType()); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private static class Employee { - private String name; - private Double salary; - - public Employee(String name, Double salary) { - this.name = name; - this.salary = salary; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Double getSalary() { - return salary; - } - - public void setSalary(Double age) { - this.salary = salary; - } - } -} diff --git a/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java new file mode 100644 index 0000000000..e232121048 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.objecttomap; + +import static org.junit.Assert.assertEquals; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import org.junit.Test; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public class ObjectToMapUnitTest { + Employee employee = new Employee("John", 3000.0); + + @Test + public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { + Map map = convertUsingReflection(employee); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + private Map convertUsingReflection(Object object) throws IllegalAccessException { + Map map = new HashMap<>(); + Field[] fields = object.getClass().getDeclaredFields(); + + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(object)); + } + + return map; + } + + @Test + public void givenJavaObject_whenUsingJackson_thenConvertToMap() { + ObjectMapper objectMapper = new ObjectMapper(); + Map map = objectMapper.convertValue(employee, new TypeReference>() {}); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void givenJavaObject_whenUsingGson_thenConvertToMap() { + Gson gson = new Gson(); + String json = gson.toJson(employee); + Map map = gson.fromJson(json, new TypeToken>() {}.getType()); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void given_UnsortedMap_whenSortingByValueDescending_thenValuesAreInDescendingOrder() { + Map unsortedMap = new HashMap<>(); + unsortedMap.put("one", 1); + unsortedMap.put("three", 3); + unsortedMap.put("five", 5); + unsortedMap.put("two", 2); + unsortedMap.put("four", 4); + + Map sortedMap = sortMapByValueDescending(unsortedMap); + + assertEquals(5, sortedMap.size()); + final Iterator iterator = sortedMap.values().iterator(); + assertEquals(5, (int) iterator.next()); + assertEquals(4, (int) iterator.next()); + assertEquals(3, (int) iterator.next()); + assertEquals(2, (int) iterator.next()); + assertEquals(1, (int) iterator.next()); + } + + @Test + public void given_UnsortedMap_whenUsingTreeMap_thenKeysAreInDescendingOrder() { + SortedMap treeMap = new TreeMap<>(Comparator.reverseOrder()); + treeMap.put("one", 1); + treeMap.put("three", 3); + treeMap.put("five", 5); + treeMap.put("two", 2); + treeMap.put("four", 4); + + assertEquals(5, treeMap.size()); + final Iterator iterator = treeMap.keySet().iterator(); + assertEquals("two", iterator.next()); + assertEquals("three", iterator.next()); + assertEquals("one", iterator.next()); + assertEquals("four", iterator.next()); + assertEquals("five", iterator.next()); + } + + private static class Employee { + private String name; + private Double salary; + + public Employee(String name, Double salary) { + this.name = name; + this.salary = salary; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getSalary() { + return salary; + } + + public void setSalary(Double age) { + this.salary = salary; + } + } + + public static > Map sortMapByValueDescending(Map map) { + return map.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } +} From b2295ce3b7795a953fed0a0163fdcb26476da060 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:14:32 +0800 Subject: [PATCH 049/135] Update README.md [skip ci] --- core-java-modules/core-java-arrays-operations-advanced/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/core-java-modules/core-java-arrays-operations-advanced/README.md b/core-java-modules/core-java-arrays-operations-advanced/README.md index 0647d89d16..b379958f37 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced/README.md @@ -14,4 +14,3 @@ This module contains articles about advanced operations on arrays in Java. They - [Slicing Arrays in Java](https://www.baeldung.com/java-slicing-arrays) - [Combining Two or More Byte Arrays](https://www.baeldung.com/java-concatenate-byte-arrays) - [Calculating the Sum of Two Arrays in Java](https://www.baeldung.com/java-sum-arrays-element-wise) -- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) From 823d0efb332a653dffa62bd86e3976c589f4caac Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:16:10 +0800 Subject: [PATCH 050/135] Create README.md [skip ci] --- .../core-java-arrays-operations-advanced-2/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 core-java-modules/core-java-arrays-operations-advanced-2/README.md diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/README.md b/core-java-modules/core-java-arrays-operations-advanced-2/README.md new file mode 100644 index 0000000000..17ffa2562d --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) From af59c6a5397d420e5999c9677dfb0912ae6bb92d Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:53:50 +0800 Subject: [PATCH 051/135] Update README.md [skip ci] --- persistence-modules/spring-jdbc/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/spring-jdbc/README.md b/persistence-modules/spring-jdbc/README.md index 21d25915de..19f8537a4e 100644 --- a/persistence-modules/spring-jdbc/README.md +++ b/persistence-modules/spring-jdbc/README.md @@ -7,3 +7,4 @@ - [Obtaining Auto-generated Keys in Spring JDBC](https://www.baeldung.com/spring-jdbc-autogenerated-keys) - [Spring JDBC Batch Inserts](https://www.baeldung.com/spring-jdbc-batch-inserts) - [Fix EmptyResultDataAccessException When Using JdbcTemplate](https://www.baeldung.com/jdbctemplate-fix-emptyresultdataaccessexception) +- [How to replace deprecated jdbcTemplate.queryForObject and jdbcTemplate.query in spring boot 2.4.X and above](https://www.baeldung.com/spring-boot-replace-deprecated-jdbctemplate-queryforobject-query) From 95946165620b8131bffca2679cc59e651b4eae19 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:56:54 +0800 Subject: [PATCH 052/135] Update README.md [skip ci] --- core-java-modules/core-java-string-algorithms-3/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-string-algorithms-3/README.md b/core-java-modules/core-java-string-algorithms-3/README.md index 2bb70f5c97..3ef07129ed 100644 --- a/core-java-modules/core-java-string-algorithms-3/README.md +++ b/core-java-modules/core-java-string-algorithms-3/README.md @@ -11,4 +11,5 @@ This module contains articles about string-related algorithms. - [Find the First Non Repeating Character in a String in Java](https://www.baeldung.com/java-find-the-first-non-repeating-character) - [Find the First Embedded Occurrence of an Integer in a Java String](https://www.baeldung.com/java-string-find-embedded-integer) - [Find the Most Frequent Characters in a String](https://www.baeldung.com/java-string-find-most-frequent-characters) -- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) \ No newline at end of file +- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) +- [Check if Letter Is Emoji With Java](https://www.baeldung.com/java-check-letter-emoji) From 14971d6017f3d7851b204185d78d2f8af3fe848e Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:59:09 +0800 Subject: [PATCH 053/135] Update README.md [skip ci] --- core-java-modules/core-java-9-streams/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-9-streams/README.md b/core-java-modules/core-java-9-streams/README.md index 0ad8500689..d9663e0858 100644 --- a/core-java-modules/core-java-9-streams/README.md +++ b/core-java-modules/core-java-9-streams/README.md @@ -4,3 +4,4 @@ This module contains articles about Java 9 streams ### Relevant Articles: - [How to Break from Java Stream forEach](https://www.baeldung.com/java-break-stream-foreach) +- [Creating Stream of Regex Matches](https://www.baeldung.com/java-stream-regex-matches) From 3d09f92af7121c5de8736f10ed4e308f517c02e0 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:02:38 +0800 Subject: [PATCH 054/135] Update README.md [skip ci] --- core-java-modules/core-java-io-apis-2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-io-apis-2/README.md b/core-java-modules/core-java-io-apis-2/README.md index cc3c351afc..3ec3220424 100644 --- a/core-java-modules/core-java-io-apis-2/README.md +++ b/core-java-modules/core-java-io-apis-2/README.md @@ -7,3 +7,4 @@ This module contains articles about core Java input/output(IO) APIs. - [Get the Desktop Path in Java](https://www.baeldung.com/java-desktop-path) - [Check if a File Is Empty in Java](https://www.baeldung.com/java-check-file-empty) - [Converting Relative to Absolute Paths in Java](https://www.baeldung.com/java-from-relative-to-absolute-paths) +- [Detect EOF in Java](https://www.baeldung.com/java-file-detect-end-of-file) From c731ff9446380a99271e794f7d27d8b9750166b3 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:12:27 +0800 Subject: [PATCH 055/135] Update README.md [skip ci] --- core-java-modules/core-java-numbers-6/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-numbers-6/README.md b/core-java-modules/core-java-numbers-6/README.md index 254b2b58d7..3bd9fe6ddb 100644 --- a/core-java-modules/core-java-numbers-6/README.md +++ b/core-java-modules/core-java-numbers-6/README.md @@ -4,4 +4,5 @@ - [Integer.class vs Integer.TYPE vs int.class](https://www.baeldung.com/java-integer-class-vs-type-vs-int) - [Does Java Read Integers in Little Endian or Big Endian?](https://www.baeldung.com/java-integers-little-big-endian) - [How to Split an Integer Number Into Digits in Java](https://www.baeldung.com/java-integer-individual-digits) +- [Java Double vs. BigDecimal](https://www.baeldung.com/java-double-vs-bigdecimal) - More articles: [[<-- prev]](../core-java-numbers-5) From 520f7d508d05f0a1b9234f555ead3b65dfa65141 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:15:40 +0800 Subject: [PATCH 056/135] Create README.md [skip ci] --- apache-poi-3/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apache-poi-3/README.md diff --git a/apache-poi-3/README.md b/apache-poi-3/README.md new file mode 100644 index 0000000000..58ddc8b41c --- /dev/null +++ b/apache-poi-3/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How To Convert Excel Data Into List Of Java Objects](https://www.baeldung.com/java-convert-excel-data-into-list) From dd1503b6e07161e25257212dce0f78856d5598ac Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:19:11 +0800 Subject: [PATCH 057/135] Update README.md [skip ci] --- core-java-modules/core-java-arrays-guides/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-arrays-guides/README.md b/core-java-modules/core-java-arrays-guides/README.md index 0af77980af..d8b0d126a1 100644 --- a/core-java-modules/core-java-arrays-guides/README.md +++ b/core-java-modules/core-java-arrays-guides/README.md @@ -9,3 +9,4 @@ This module contains complete guides about arrays in Java - [Guide to ArrayStoreException](https://www.baeldung.com/java-arraystoreexception) - [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array) - [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size) +- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates) From 21ae31a8ef66d5e4d56dde84daf7bc4a1348006f Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:23:11 +0800 Subject: [PATCH 058/135] Update README.md [skip ci] --- spring-boot-modules/spring-boot-security/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-modules/spring-boot-security/README.md b/spring-boot-modules/spring-boot-security/README.md index d848f798ba..2fd9e77c92 100644 --- a/spring-boot-modules/spring-boot-security/README.md +++ b/spring-boot-modules/spring-boot-security/README.md @@ -11,7 +11,7 @@ This module contains articles about Spring Boot Security - [Disable Security for a Profile in Spring Boot](https://www.baeldung.com/spring-security-disable-profile) - [Spring @EnableWebSecurity vs. @EnableGlobalMethodSecurity](https://www.baeldung.com/spring-enablewebsecurity-vs-enableglobalmethodsecurity) - [Spring Security – Configuring Different URLs](https://www.baeldung.com/spring-security-configuring-urls) - +- [Difference Between permitAll() and anonymous() in Spring Security](https://www.baeldung.com/spring-security-permitall-vs-anonymous) ### Spring Boot Security Auto-Configuration From 29bfc410bcda58ce2f020542f053afbfd820d2e9 Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 29 Sep 2023 21:03:32 +0530 Subject: [PATCH 059/135] Update pom.xml --- .../pom.xml | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index 44ecb0fffb..2ab88c9944 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -1,31 +1,32 @@ - 4.0.0 - core-java-collections-array-list-2 - core-java-collections-array-list-2 - jar - - com.baeldung.core-java-modules - core-java-modules - 0.0.1-SNAPSHOT - + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + core-java-collections-array-list-2 + core-java-collections-array-list-2 + jar + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven-compiler-plugin.source} - ${maven-compiler-plugin.target} - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + - - 17 - 17 - + + 17 + 17 + From d109a6bcb5847323850dd59051f439e9a353fd1a Mon Sep 17 00:00:00 2001 From: Niket Agrawal Date: Fri, 29 Sep 2023 21:04:56 +0530 Subject: [PATCH 060/135] Updated POM Formatting --- .../core-java-collections-array-list-2/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml index 2ab88c9944..042f6e5bb5 100644 --- a/core-java-modules/core-java-collections-array-list-2/pom.xml +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-collections-array-list-2 core-java-collections-array-list-2 From 6a7f88cbbdbd16b9d4b9d637084ad75ec953f6b7 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:06:01 +0800 Subject: [PATCH 061/135] Update README.md [skip ci] --- core-java-modules/core-java-16/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-16/README.md b/core-java-modules/core-java-16/README.md index b2740d194c..11b0fba8d3 100644 --- a/core-java-modules/core-java-16/README.md +++ b/core-java-modules/core-java-16/README.md @@ -5,3 +5,4 @@ - [Collecting Stream Elements into a List in Java](https://www.baeldung.com/java-stream-to-list-collecting) - [New Features in Java 16](https://www.baeldung.com/java-16-new-features) - [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector) +- [Value-Based Classes in Java](https://www.baeldung.com/java-value-based-classes) From 55c8c26ef99cf522873365f4f69204f17cac7d1a Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:08:32 +0800 Subject: [PATCH 062/135] Update README.md [skip ci] --- logging-modules/log4j2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/logging-modules/log4j2/README.md b/logging-modules/log4j2/README.md index 87e92e0d48..fa7133ffdd 100644 --- a/logging-modules/log4j2/README.md +++ b/logging-modules/log4j2/README.md @@ -9,3 +9,4 @@ - [Log4j 2 Plugins](https://www.baeldung.com/log4j2-plugins) - [Printing Thread Info in Log File Using Log4j2](https://www.baeldung.com/log4j2-print-thread-info) - [Log4j2 – Logging to Both File and Console](https://www.baeldung.com/java-log4j2-file-and-console) +- [Log4j 2 Configuration Using a Properties File](https://www.baeldung.com/java-log4j2-config-with-prop-file) From 38d88c7eec7943dabec75c57d4088ceeafa3d013 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:11:58 +0800 Subject: [PATCH 063/135] Update README.md [skip ci] --- apache-poi-3/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apache-poi-3/README.md b/apache-poi-3/README.md index 58ddc8b41c..9e9d6a94eb 100644 --- a/apache-poi-3/README.md +++ b/apache-poi-3/README.md @@ -1,2 +1,3 @@ ## Relevant Articles - [How To Convert Excel Data Into List Of Java Objects](https://www.baeldung.com/java-convert-excel-data-into-list) +- [Expand Columns with Apache POI](https://www.baeldung.com/java-apache-poi-expand-columns) From d73922fd580cfcbb347cc7e8b36434bac78d8d45 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:16:32 +0800 Subject: [PATCH 064/135] Update README.md [skip ci] --- logging-modules/log4j/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index a47d0ae89b..32ea358369 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -4,3 +4,4 @@ - [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders) - [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions) - [Log4j Warning: “No Appenders Could Be Found for Logger”](https://www.baeldung.com/log4j-no-appenders-found) +- [A Guide to Log4j and the log4j.properties File in Java](https://www.baeldung.com/java-log4j-properties-guide) From fe818359cce4572cb8bd9fdc905c4a812698017e Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:21:44 +0800 Subject: [PATCH 065/135] Update README.md [skip ci] --- testing-modules/mockito-2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md index b60885c6d5..da8f339e56 100644 --- a/testing-modules/mockito-2/README.md +++ b/testing-modules/mockito-2/README.md @@ -8,3 +8,4 @@ This module contains articles about Mockito - [Matching Null With Mockito](https://www.baeldung.com/mockito-match-null) - [Mock Same Method with Different Parameters](https://www.baeldung.com/java-mock-same-method-other-parameters) - [How to Mock Constructors for Unit Testing using Mockito](https://www.baeldung.com/java-mockito-constructors-unit-testing) +- [Overview of Mockito MockedConstruction](https://www.baeldung.com/java-mockito-mockedconstruction) From ac1d97801d0f8ee59af2b47715b27f87518eb8af Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:27:07 +0800 Subject: [PATCH 066/135] Update README.md [skip ci] --- core-java-modules/core-java-documentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-modules/core-java-documentation/README.md b/core-java-modules/core-java-documentation/README.md index b66b9e8c05..972e76c165 100644 --- a/core-java-modules/core-java-documentation/README.md +++ b/core-java-modules/core-java-documentation/README.md @@ -3,4 +3,4 @@ ### Relevant Articles: - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - +- [Code Snippets in Java API Documentation](https://www.baeldung.com/java-doc-code-snippets) From aebe7fa26b2f56596a5a17dae9cf291cb6e62669 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:29:54 +0800 Subject: [PATCH 067/135] Update README.md [skip ci] --- core-java-modules/core-java-21/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md index 04f99a244b..2c51db275a 100644 --- a/core-java-modules/core-java-21/README.md +++ b/core-java-modules/core-java-21/README.md @@ -1,2 +1,3 @@ ## Relevant Articles -- [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) \ No newline at end of file +- [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) +- [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates) From 8faea6ae1330be27ee2c699ab4bbc324974eb6c7 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:33:33 +0800 Subject: [PATCH 068/135] Create README.md [skip ci] --- core-java-modules/core-java-collections-list-6/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 core-java-modules/core-java-collections-list-6/README.md diff --git a/core-java-modules/core-java-collections-list-6/README.md b/core-java-modules/core-java-collections-list-6/README.md new file mode 100644 index 0000000000..fd162743dc --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Check if a List Contains a String Element While Ignoring Case](https://www.baeldung.com/java-list-search-case-insensitive) From 1775ac73f03b303a9cfa4e9fb1f5fc4e230e7d2e Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Sat, 30 Sep 2023 17:27:47 +0330 Subject: [PATCH 069/135] #BAEL-6916: add indentation and private access --- .../camel/jackson/FruitListJacksonUnmarshalUnitTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index bb31884d11..8120eeffec 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -32,7 +32,7 @@ import static org.springframework.test.util.AssertionErrors.assertNotNull; public class FruitListJacksonUnmarshalUnitTest { @Autowired - ProducerTemplate template; + private ProducerTemplate template; @EndpointInject("mock:marshalledObject") private MockEndpoint mock; @@ -44,8 +44,8 @@ public class FruitListJacksonUnmarshalUnitTest { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) - .to("mock:marshalledObject"); + from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) + .to("mock:marshalledObject"); } }; } From fad02f73d2cf9c22bb329f04b59044192d019222 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 30 Sep 2023 18:08:57 +0300 Subject: [PATCH 070/135] BAEL-6847 move article --- core-java-modules/core-java-string-operations-5/README.md | 1 - core-java-modules/core-java-string-operations-6/README.md | 2 ++ .../test/java/com/baeldung/replace/ReplaceStringUnitTest.java | 0 3 files changed, 2 insertions(+), 1 deletion(-) rename core-java-modules/{core-java-string-operations-5 => core-java-string-operations-6}/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java (100%) diff --git a/core-java-modules/core-java-string-operations-5/README.md b/core-java-modules/core-java-string-operations-5/README.md index fda7f39654..dffd3c1ab6 100644 --- a/core-java-modules/core-java-string-operations-5/README.md +++ b/core-java-modules/core-java-string-operations-5/README.md @@ -11,4 +11,3 @@ - [Check if the First Letter of a String Is a Number](https://www.baeldung.com/java-check-if-string-starts-with-number) - [Print “” Quotes Around a String in Java](https://www.baeldung.com/java-string-print-quotes) - [Remove Punctuation From a String in Java](https://www.baeldung.com/java-remove-punctuation-from-string) -- [Replacing Single Quote with \’ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) diff --git a/core-java-modules/core-java-string-operations-6/README.md b/core-java-modules/core-java-string-operations-6/README.md index 853d58287d..b4b78d1ad7 100644 --- a/core-java-modules/core-java-string-operations-6/README.md +++ b/core-java-modules/core-java-string-operations-6/README.md @@ -10,3 +10,5 @@ - [Check if a String Contains Non-Alphanumeric Characters](https://www.baeldung.com/java-string-test-special-characters) - [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars) - [Performance Comparison Between Different Java String Concatenation Methods](https://www.baeldung.com/java-string-concatenation-methods) +- [Replacing Single Quote with \’ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) + diff --git a/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java similarity index 100% rename from core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java rename to core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java From 306f1335b8e25ebcf13c6911f33de3ff9901b17d Mon Sep 17 00:00:00 2001 From: Anton Dalagan Date: Sat, 30 Sep 2023 17:39:12 +0200 Subject: [PATCH 071/135] Bael 6962 convert double to float in java (#14883) * Commit 1 - Anton Dalagan Code for Evaluation article. Contains Unit tests, domain class, and App main method. * BAEL-6962 - Created unit test, and updated pom.xml * BAEL-6962 - Removed files unrelated to the article * BAEL-6962 - Added a declartions for float and double in diff class. Updated unit tests. --- .../core-java-numbers-conversions/pom.xml | 12 +++++++ .../FloatAndDoubleConversions.java | 15 +++++++++ .../FloatDoubleConversionsTest.java | 33 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java create mode 100644 core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java diff --git a/core-java-modules/core-java-numbers-conversions/pom.xml b/core-java-modules/core-java-numbers-conversions/pom.xml index f745b83f8a..d014675ead 100644 --- a/core-java-modules/core-java-numbers-conversions/pom.xml +++ b/core-java-modules/core-java-numbers-conversions/pom.xml @@ -18,6 +18,18 @@ commons-lang3 ${commons-lang3.version} + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + diff --git a/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java new file mode 100644 index 0000000000..f4fd68550c --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java @@ -0,0 +1,15 @@ +package com.baeldung.floatdoubleconversions; + +public class FloatAndDoubleConversions { + public static void main(String args[]){ + float vatRate = 14.432511f; + System.out.println("vatRate:"+vatRate); + Float localTaxRate = 20.12434f; + System.out.println("localTaxRate:"+localTaxRate); + + double shootingAverage = 56.00000000000001; + System.out.println("shootingAverage:"+shootingAverage); + Double assistAverage = 81.123000000045; + System.out.println("assistAverage:"+assistAverage); + } +} diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java new file mode 100644 index 0000000000..10e9fd4c36 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java @@ -0,0 +1,33 @@ +package com.baeldung.floatdoubleconversions; + +import org.junit.Assert; +import org.junit.Test; + +public class FloatDoubleConversionsTest { + + @Test + public void whenDoubleType_thenFloatTypeSuccess(){ + double interestRatesYearly = 13.333333333333334; + float interest = (float) interestRatesYearly; + System.out.println(interest); //13.333333 + Assert.assertTrue(Float.class.isInstance(interest));//true + + Double monthlyRates = 2.111111111111112; + float rates = monthlyRates.floatValue(); + System.out.println(rates); //2.1111112 + Assert.assertTrue(Float.class.isInstance(rates));//true + } + @Test + public void whenFloatType_thenDoubleTypeSuccess(){ + float gradeAverage =2.05f; + double average = gradeAverage; + System.out.println(average); //2.049999952316284 + Assert.assertTrue(Double.class.isInstance(average));//true + + Float monthlyRates = 2.1111112f; + Double rates = monthlyRates.doubleValue(); + System.out.println(rates); //2.1111112 + Assert.assertTrue(Double.class.isInstance(rates));//true + } + +} From 88ea37c981bb68e0e59c0d22f021381e5335e1d3 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Thu, 21 Sep 2023 23:59:34 +0530 Subject: [PATCH 072/135] BAEL-5889: Added code for Spy and SpyBean difference implementation --- .../baeldung/spytest/NotificationService.java | 11 +++++ .../main/java/com/baeldung/spytest/Order.java | 41 +++++++++++++++++++ .../com/baeldung/spytest/OrderRepository.java | 19 +++++++++ .../com/baeldung/spytest/OrderService.java | 21 ++++++++++ .../baeldung/spytest/SpyTestApplication.java | 12 ++++++ .../spytest/OrderServiceIntegrationTest.java | 32 +++++++++++++++ .../spytest/OrderServiceUnitTest.java | 39 ++++++++++++++++++ .../RunApplicationIntegrationTest.java | 1 + 8 files changed, 176 insertions(+) create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java new file mode 100644 index 0000000000..521e3b076e --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java @@ -0,0 +1,11 @@ +package com.baeldung.spytest; + +import org.springframework.stereotype.Component; + +@Component +public class NotificationService { + public void notify(Order order){ + System.out.println(order); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java new file mode 100644 index 0000000000..b7d7fad9e3 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java @@ -0,0 +1,41 @@ +package com.baeldung.spytest; + +import java.util.UUID; + +public class Order { + + private UUID id; + + private String name; + + private double orderQuantity; + + private String address; + + public Order(UUID id, String name, double orderQuantity, String address) { + this.id = id; + this.name = name; + this.orderQuantity = orderQuantity; + this.address = address; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public double getOrderQuantity() { + return orderQuantity; + } + + public String getAddress() { + return address; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java new file mode 100644 index 0000000000..986f7abde2 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.spytest; + +import java.util.HashMap; +import java.util.UUID; + +import org.springframework.stereotype.Component; + +@Component +public class OrderRepository { + + public static final HashMap orders=new HashMap<>(); + + public Order save(Order order) { + UUID orderId = UUID.randomUUID(); + order.setId(orderId); + orders.put(UUID.randomUUID(), order); + return order; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java new file mode 100644 index 0000000000..d08c96f5ae --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java @@ -0,0 +1,21 @@ +package com.baeldung.spytest; + +import org.springframework.stereotype.Service; + +@Service +public class OrderService { + + public final OrderRepository orderRepository; + + public final NotificationService notificationService; + + public OrderService(OrderRepository orderRepository, NotificationService notificationService) { + this.orderRepository = orderRepository; + this.notificationService = notificationService; + } + public Order save(Order order) { + order = orderRepository.save(order); + notificationService.notify(order); + return order; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java new file mode 100644 index 0000000000..bb2d3dc7d2 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spytest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +@SpringBootApplication +public class SpyTestApplication { + + public static void main(String[] args) { + SpringApplication.run(SpyTestApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java new file mode 100644 index 0000000000..22b0388b13 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java @@ -0,0 +1,32 @@ +package com.baeldung.spytest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; + +@SpringBootTest +class OrderServiceIntegrationTest { + + @Autowired + OrderRepository orderRepository; + @SpyBean + NotificationService notificationService; + @SpyBean + OrderService orderService; + + @Test + void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() { + + Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); + Order order = orderService.save(orderInput); + Assertions.assertNotNull(order); + Assertions.assertNotNull(order.getId()); + verify(notificationService).notify(any(Order.class)); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java new file mode 100644 index 0000000000..b8f18c804c --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.spytest; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import java.util.UUID; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class OrderServiceUnitTest { + + @Spy + OrderRepository orderRepository; + @Spy + NotificationService notificationService; + @InjectMocks + OrderService orderService; + + @Test + void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() { + + UUID orderId = UUID.randomUUID(); + Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); + doReturn(orderInput).when(orderRepository) + .save(any()); + Order order = orderService.save(orderInput); + Assertions.assertNotNull(order); + Assertions.assertEquals(orderId, order.getId()); + verify(notificationService).notify(any(Order.class)); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java index 26a7339f1d..3a8b74829e 100644 --- a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java +++ b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java @@ -1,6 +1,7 @@ package com.baeldung.prevent.commandline.application.runner.execution; import org.junit.jupiter.api.Test; +import org.mockito.Spy; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.SpyBean; From 14f336cf1a3d249f5e4228116e93396f477464e6 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Fri, 22 Sep 2023 00:01:01 +0530 Subject: [PATCH 073/135] BAEL-5889: Removed unnecessary change --- .../runner/execution/RunApplicationIntegrationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java index 3a8b74829e..26a7339f1d 100644 --- a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java +++ b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/prevent/commandline/application/runner/execution/RunApplicationIntegrationTest.java @@ -1,7 +1,6 @@ package com.baeldung.prevent.commandline.application.runner.execution; import org.junit.jupiter.api.Test; -import org.mockito.Spy; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.SpyBean; From f324a501654d71fa3cf1ae04cb4992bae27ba3b8 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Sat, 23 Sep 2023 16:11:32 +0530 Subject: [PATCH 074/135] BAEL-5889: Updated with review comment to add another method inside @Spy which is served through a mock to demonstrate partial mock condition --- .../java/com/baeldung/spytest/ExternalAlertService.java | 6 ++++++ .../java/com/baeldung/spytest/NotificationService.java | 9 ++++++++- .../src/main/java/com/baeldung/spytest/Order.java | 8 ++++++++ .../main/java/com/baeldung/spytest/OrderRepository.java | 2 +- .../src/main/java/com/baeldung/spytest/OrderService.java | 4 ++++ .../java/com/baeldung/spytest/SpyTestApplication.java | 1 + .../baeldung/spytest/OrderServiceIntegrationTest.java | 3 +++ .../java/com/baeldung/spytest/OrderServiceUnitTest.java | 2 ++ 8 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java new file mode 100644 index 0000000000..fd321a0e68 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java @@ -0,0 +1,6 @@ +package com.baeldung.spytest; + +public interface ExternalAlertService { + public boolean alert(Order order); + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java index 521e3b076e..f0b2f92bee 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java @@ -4,8 +4,15 @@ import org.springframework.stereotype.Component; @Component public class NotificationService { - public void notify(Order order){ + + private ExternalAlertService externalAlertService; + + public void notify(Order order) { System.out.println(order); } + public boolean raiseAlert(Order order) { + return externalAlertService.alert(order); + } + } diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java index b7d7fad9e3..23f5a05e9d 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java @@ -8,6 +8,8 @@ public class Order { private String name; + private OrderType orderType; + private double orderQuantity; private String address; @@ -19,6 +21,10 @@ public class Order { this.address = address; } + public enum OrderType { + INDIVIDUAL, BULK; + } + public UUID getId() { return id; } @@ -39,3 +45,5 @@ public class Order { return address; } } + + diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java index 986f7abde2..90fe5ba2b8 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component; @Component public class OrderRepository { - public static final HashMap orders=new HashMap<>(); + public static final HashMap orders = new HashMap<>(); public Order save(Order order) { UUID orderId = UUID.randomUUID(); diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java index d08c96f5ae..47647b8721 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java @@ -13,9 +13,13 @@ public class OrderService { this.orderRepository = orderRepository; this.notificationService = notificationService; } + public Order save(Order order) { order = orderRepository.save(order); notificationService.notify(order); + if (!notificationService.raiseAlert(order)) { + throw new RuntimeException("Alert not raised"); + } return order; } } diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java index bb2d3dc7d2..d8d81378df 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java @@ -2,6 +2,7 @@ package com.baeldung.spytest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; + @SpringBootApplication public class SpyTestApplication { diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java index 22b0388b13..96c7b09dfc 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java @@ -1,6 +1,7 @@ package com.baeldung.spytest; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import org.junit.jupiter.api.Assertions; @@ -23,6 +24,8 @@ class OrderServiceIntegrationTest { void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() { Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); + doReturn(true).when(notificationService) + .raiseAlert(any(Order.class)); Order order = orderService.save(orderInput); Assertions.assertNotNull(order); Assertions.assertNotNull(order.getId()); diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java index b8f18c804c..21ae849bcf 100644 --- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java @@ -30,6 +30,8 @@ class OrderServiceUnitTest { Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP"); doReturn(orderInput).when(orderRepository) .save(any()); + doReturn(true).when(notificationService) + .raiseAlert(any(Order.class)); Order order = orderService.save(orderInput); Assertions.assertNotNull(order); Assertions.assertEquals(orderId, order.getId()); From 87056d13bc8b6a6b423b0c84b568f39cfeb1fd10 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Sun, 1 Oct 2023 07:28:57 +0530 Subject: [PATCH 075/135] BAEL-7032: Improvement to conditional mapping by using @Condition and added tests --- .../baeldung/expression/dto/LicenseDto.java | 10 +++++++ .../expression/mapper/LicenseMapper.java | 12 +++++++- .../baeldung/expression/model/License.java | 16 ++++++++++- .../mapper/LicenseMapperUnitTest.java | 28 +++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java index 025df1a4f6..1d7cacaead 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java +++ b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java @@ -11,6 +11,8 @@ public class LicenseDto { private LocalDateTime endDate; + private String licenseType; + public UUID getId() { return id; } @@ -35,4 +37,12 @@ public class LicenseDto { this.endDate = endDate; } + public String getLicenseType() { + return licenseType; + } + + public void setLicenseType(String licenseType) { + this.licenseType = licenseType; + } + } diff --git a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java index 100588b45d..0d8904e220 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java +++ b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java @@ -6,6 +6,7 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.mapstruct.AfterMapping; +import org.mapstruct.Condition; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; @@ -40,4 +41,13 @@ public interface LicenseMapper { .toDays() <= 14; } -} + @Condition + default boolean mapsToExpectedLicenseType(String licenseType) { + try { + return licenseType != null && License.LicenseType.valueOf(licenseType) != null; + } catch (IllegalArgumentException e) { + return false; + } + } + +} \ No newline at end of file diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java index 71e4f086c0..550d23eee8 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/model/License.java +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -16,6 +16,8 @@ public class License { private boolean renewalRequired; + private LicenseType licenseType; + public UUID getId() { return id; } @@ -55,4 +57,16 @@ public class License { public void setRenewalRequired(boolean renewalRequired) { this.renewalRequired = renewalRequired; } -} + + public enum LicenseType { + INDIVIDUAL, FAMILY + } + + public LicenseType getLicenseType() { + return licenseType; + } + + public void setLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + } +} \ No newline at end of file diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java index dcdda5c1ac..8c015674bc 100644 --- a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -6,6 +6,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.UUID; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; @@ -74,4 +75,31 @@ class LicenseMapperUnitTest { assertThat(license.getId()).isSameAs(id); } + @Test + void givenLicenseDtoWithoutLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithInvalidLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("invalid_license_type"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithValidLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithMatchingLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("INDIVIDUAL"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNotNull(license.getLicenseType()); + assertThat(license.getLicenseType()).isEqualTo(License.LicenseType.INDIVIDUAL); + } + } \ No newline at end of file From 96de260e1dbfbcc65495dfac7969cc5ef5abb2d9 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Sun, 1 Oct 2023 07:30:17 +0530 Subject: [PATCH 076/135] BAEL-7032: updated formatting --- .../src/main/java/com/baeldung/expression/model/License.java | 1 - 1 file changed, 1 deletion(-) diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java index 550d23eee8..e36e278a57 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/model/License.java +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -3,7 +3,6 @@ package com.baeldung.expression.model; import java.time.OffsetDateTime; import java.util.UUID; - public class License { private UUID id; From 9c17051f2af28123814aba0c811a99e40e0e3681 Mon Sep 17 00:00:00 2001 From: hmdrzsharifi Date: Sun, 1 Oct 2023 13:31:41 +0330 Subject: [PATCH 077/135] #BAEL-7076: add indentation --- .../camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index df7a57a984..ab5993d816 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -45,8 +45,8 @@ public class FruitArrayJacksonUnmarshalUnitTest { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) - .to("mock:marshalledObject"); + from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) + .to("mock:marshalledObject"); } }; } From ae29eca0f8188b12b71ea8430ffa429535cf694b Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Sun, 1 Oct 2023 12:22:34 -0300 Subject: [PATCH 078/135] BAEL-6927: Update article "Understanding Kafka Topics and Partitions" (#14837) * consumer config. topic config. driver and calculator classes. * basic app working. test structure * final version * wraping up * optimizing imports * comments changes * addressing improvement changes --- .../TemperatureConsumer.java | 17 +++++------------ ...KafkaTopicsAndPartitionsIntegrationTest.java | 4 +--- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java index 7cfbdd5fb0..2919ae1d7b 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java @@ -8,29 +8,22 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; @Service public class TemperatureConsumer { - private CountDownLatch latch = new CountDownLatch(1); - Map> consumedRecords = new ConcurrentHashMap<>(); @KafkaListener(topics = "celcius-scale-topic", groupId = "group-1") public void consumer1(ConsumerRecord consumerRecord) { - computeConsumedRecord("consumer-1", consumerRecord.partition()); + trackConsumedPartitions("consumer-1", consumerRecord.partition()); } - private void computeConsumedRecord(String key, int consumerRecord) { - consumedRecords.computeIfAbsent(key, k -> new HashSet<>()); - consumedRecords.computeIfPresent(key, (k, v) -> { - v.add(String.valueOf(consumerRecord)); + private void trackConsumedPartitions(String consumerName, int partitionNumber) { + consumedRecords.computeIfAbsent(consumerName, k -> new HashSet<>()); + consumedRecords.computeIfPresent(consumerName, (k, v) -> { + v.add(String.valueOf(partitionNumber)); return v; }); } - - public CountDownLatch getLatch() { - return latch; - } } diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java index 309c87125a..de720ef955 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java @@ -7,8 +7,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.kafka.test.EmbeddedKafkaBroker; import org.springframework.kafka.test.context.EmbeddedKafka; -import java.util.concurrent.TimeUnit; - @SpringBootTest(classes = ThermostatApplicationKafkaApp.class) @EmbeddedKafka(partitions = 2, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) public class KafkaTopicsAndPartitionsIntegrationTest { @@ -24,7 +22,7 @@ public class KafkaTopicsAndPartitionsIntegrationTest { @Test public void givenTopic_andConsumerGroup_whenConsumersListenToEvents_thenConsumeItCorrectly() throws Exception { service.measureCelsiusAndPublish(10000); - consumer.getLatch().await(1, TimeUnit.SECONDS); + Thread.sleep(1000); System.out.println(consumer.consumedRecords); } } From 9ca51279aee091b53da22a5621cba4239d8e569d Mon Sep 17 00:00:00 2001 From: Maiklins Date: Sun, 1 Oct 2023 21:56:19 +0200 Subject: [PATCH 079/135] Update README.md --- core-java-modules/core-java-collections-array-list-2/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md index 00c3e8d9b7..dbf5c47edb 100644 --- a/core-java-modules/core-java-collections-array-list-2/README.md +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -2,4 +2,5 @@ This module contains articles about the Java ArrayList collection -### Relevant Articles: \ No newline at end of file +### Relevant Articles: +- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/arraylist-with-multiple-object-types) From 39c353c6aeec68b85418da16a3907a98ef9869ea Mon Sep 17 00:00:00 2001 From: mcasari Date: Sun, 1 Oct 2023 21:58:55 +0200 Subject: [PATCH 080/135] BAEL-6846 - updates due to further discussion about float representation --- .../FloatToBigDecimalUnitTest.java | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index 2d6d1ab5d0..8895c01575 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -16,45 +16,44 @@ class FloatToBigDecimalUnitTest { } @Test - public void whenCreatedFromCertainFloatValues_thenMatches() { - float floatToConvert = 0.5f; - BigDecimal bdFromFloat = new BigDecimal(floatToConvert); - assertEquals("0.5", bdFromFloat.toString()); - } - - @Test - public void whenCreatedFromCertainFloatValues_thenDoesNotMatch() { + public void whenCreatedFromFloat_thenMatchesInternallyStoredValue() { float floatToConvert = 1.1f; BigDecimal bdFromFloat = new BigDecimal(floatToConvert); assertEquals("1.10000002384185791015625", bdFromFloat.toString()); } @Test - public void whenCreatedFromString_thenMatches() { - String floatValue = Float.toString(1.1f); - BigDecimal bdFromString = new BigDecimal(floatValue); + public void whenCreatedFromString_thenPreservesTheOriginal() { + BigDecimal bdFromString = new BigDecimal("1.1"); assertEquals("1.1", bdFromString.toString()); } @Test - public void whenCreatedByValueOfAndIsFloat_thenDoesNotMatch() { - float floatToConvert = 1.1f; - BigDecimal bdByValueOf = BigDecimal.valueOf(floatToConvert); - assertEquals("1.100000023841858", bdByValueOf.toString()); + public void whenCreatedFromFloatConvertedToString_thenFloatInternalValueGetsTruncated() { + String floatValue = Float.toString(1.1f); + BigDecimal bdFromString = new BigDecimal(floatValue); + assertEquals("1.1", floatValue); + assertEquals("1.1", bdFromString.toString()); } @Test - public void whenFloatCastToDouble_thenGotADifferentNumber() { - float floatToConvert = 1.1f; - double doubleCast = floatToConvert; - assertEquals("1.100000023841858", Double.toString(doubleCast)); + public void whenFloatConvertedToString_thenGetsTruncated() { + String floatValue = Float.toString(1.10000002384185791015625f); + assertEquals("1.1", floatValue); } @Test - public void whenCreatedByValueOfAndIsDouble_thenMatches() { - double doubleToConvert = 1.1d; - BigDecimal bdByValueOf = BigDecimal.valueOf(doubleToConvert); - assertEquals("1.1", bdByValueOf.toString()); + public void whenCreatedByValueOf_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", BigDecimal.valueOf(1.1f) + .toString()); + assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f) + .toString()); + } + + @Test + public void whenDoubleConvertsFloatToString_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", Double.toString(1.1f)); + assertEquals("1.100000023841858", Double.toString(1.10000002384185791015625f)); } } \ No newline at end of file From 071d0ca2e93c3a49dfa26f9b5a0e2a010ac33c74 Mon Sep 17 00:00:00 2001 From: brokenhardisk Date: Mon, 2 Oct 2023 07:03:58 +0200 Subject: [PATCH 081/135] BAEL-6849 Junit Tests for Interfaces in Java (#14847) * BAEL-6849 Junit Tests for Interfaces in Java * BAEL-6849 Junit Tests for Interfaces in Java * BAEL-6849 Junit Tests for Interfaces in Java * BAEL-6849 JUnit Tests for Interfaces in Java --- .../baeldung/interfaces/unittest/Circle.java | 19 +++++++++++++ .../interfaces/unittest/Rectangle.java | 21 +++++++++++++++ .../baeldung/interfaces/unittest/Shape.java | 6 +++++ .../unittest/CircleExtendsBaseUnitTest.java | 26 ++++++++++++++++++ .../interfaces/unittest/CircleUnitTest.java | 22 +++++++++++++++ .../unittest/ParameterizedUnitTest.java | 27 +++++++++++++++++++ .../RectangleExtendsBaseUnitTest.java | 26 ++++++++++++++++++ .../unittest/RectangleUnitTest.java | 22 +++++++++++++++ .../interfaces/unittest/ShapeUnitTest.java | 21 +++++++++++++++ 9 files changed, 190 insertions(+) create mode 100644 testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java create mode 100644 testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java create mode 100644 testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java create mode 100644 testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java new file mode 100644 index 0000000000..b0e63155f4 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java @@ -0,0 +1,19 @@ +package com.baeldung.interfaces.unittest; + +public class Circle implements Shape { + + private double radius; + + Circle(double radius) { + this.radius = radius; + } + + @Override + public double area() { + return 3.14 * radius * radius; + } + + public double circumference() { + return 2 * 3.14 * radius; + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java new file mode 100644 index 0000000000..a88233e83b --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +public class Rectangle implements Shape { + + private double length; + private double breadth; + + public Rectangle(double length, double breadth) { + this.length = length; + this.breadth = breadth; + } + + @Override + public double area() { + return length * breadth; + } + + public double perimeter() { + return 2 * (length + breadth); + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java new file mode 100644 index 0000000000..bac42fb246 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java @@ -0,0 +1,6 @@ +package com.baeldung.interfaces.unittest; + +public interface Shape { + + double area(); +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..08ce2bc779 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class CircleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Circle(5)); + shapeAreaMap.put("area", 78.5); + return shapeAreaMap; + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java new file mode 100644 index 0000000000..c0b4eecedc --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class CircleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape circle = new Circle(5); + double area = circle.area(); + assertEquals(78.5, area); + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java new file mode 100644 index 0000000000..6b5cd6b6ab --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class ParameterizedUnitTest { + + @ParameterizedTest + @MethodSource("data") + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful(Shape shapeInstance, double expectedArea) { + double area = shapeInstance.area(); + assertEquals(expectedArea, area); + + } + + private static Collection data() { + return Arrays.asList(new Object[][] { + { new Circle(5), 78.5 }, + { new Rectangle(4, 5), 20 } + }); + } +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..b6771ad648 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class RectangleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Rectangle(5, 4)); + shapeAreaMap.put("area", 20.0); + return shapeAreaMap; + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java new file mode 100644 index 0000000000..1983353667 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class RectangleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape rectangle = new Rectangle(5, 4); + double area = rectangle.area(); + assertEquals(20, area); + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java new file mode 100644 index 0000000000..a9d318f698 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public abstract class ShapeUnitTest { + + public abstract Map instantiateShapeWithExpectedArea(); + + @Test + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful() { + Map shapeAreaMap = instantiateShapeWithExpectedArea(); + Shape shape = (Shape) shapeAreaMap.get("shape"); + double expectedArea = (double) shapeAreaMap.get("area"); + double area = shape.area(); + assertEquals(expectedArea, area); + } +} From 2ed008decce1d050044cd79f5f5c3d077c147981 Mon Sep 17 00:00:00 2001 From: mdabrowski-eu <57441874+mdabrowski-eu@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:53:53 +0200 Subject: [PATCH 082/135] BAEL-6911 A Guide to RestClient in Spring Boot (#14893) --- spring-boot-modules/spring-boot-3/pom.xml | 61 +++++++++- .../java/com/baeldung/restclient/Article.java | 34 ++++++ .../restclient/ArticleController.java | 45 +++++++ .../restclient/RestClientApplication.java | 13 ++ .../restclient/RestClientIntegrationTest.java | 114 ++++++++++++++++++ 5 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java create mode 100644 spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java create mode 100644 spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java create mode 100644 spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index 7e61ca18af..7dd44c89dc 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -41,6 +41,27 @@ mockserver-netty ${mockserver.version} + + org.junit.jupiter + junit-jupiter + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-api + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-engine + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-params + ${jupiter.version} + test + org.mock-server mockserver-client-java @@ -187,8 +208,46 @@ 3.0.0-M7 com.baeldung.sample.TodoApplication 5.14.0 - 3.1.0 + 3.2.0-SNAPSHOT 0.2.0 + 5.10.0 + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java new file mode 100644 index 0000000000..a69d5989af --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java @@ -0,0 +1,34 @@ +package com.baeldung.restclient; + +import java.util.Objects; + +public class Article { + Integer id; + String title; + + public Article(Integer id, String title) { + this.id = id; + this.title = title; + } + + public Integer getId() { + return id; + } + + public String getTitle() { + return title; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Article article = (Article) o; + return Objects.equals(id, article.id) && Objects.equals(title, article.title); + } + + @Override + public int hashCode() { + return Objects.hash(id, title); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java new file mode 100644 index 0000000000..62922bdcee --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java @@ -0,0 +1,45 @@ +package com.baeldung.restclient; + +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@RestController +@RequestMapping("/articles") +public class ArticleController { + Map database = new HashMap<>(); + + @GetMapping + public Collection
getArticles() { + return database.values(); + } + + @GetMapping("/{id}") + public Article getArticle(@PathVariable Integer id) { + return database.get(id); + } + + @PostMapping + public void createArticle(@RequestBody Article article) { + database.put(article.getId(), article); + } + + @PutMapping("/{id}") + public void updateArticle(@PathVariable Integer id, @RequestBody Article article) { + assert Objects.equals(id, article.getId()); + database.remove(id); + database.put(id, article); + } + + @DeleteMapping("/{id}") + public void deleteArticle(@PathVariable Integer id) { + database.remove(id); + } + @DeleteMapping() + public void deleteArticles() { + database.clear(); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java new file mode 100644 index 0000000000..c411a8f74a --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.restclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RestClientApplication { + + public static void main(String[] args) { + SpringApplication.run(RestClientApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java new file mode 100644 index 0000000000..92474c88f0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java @@ -0,0 +1,114 @@ +package com.baeldung.restclient; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.MediaType; +import org.springframework.web.client.RestClient; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class RestClientIntegrationTest { + + @LocalServerPort + private int port; + private String uriBase; + RestClient restClient = RestClient.create(); + + @BeforeAll + public void setup() { + uriBase = "http://localhost:" + port; + } + + @AfterEach + public void teardown() { + restClient.delete() + .uri(uriBase + "/articles") + .retrieve() + .toBodilessEntity(); + } + + @Test + void shouldGetArticlesAndReturnString() { + String articlesAsString = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(String.class); + + assertThat(articlesAsString).isEqualTo("[]"); + } + + @Test + void shouldPostAndGetArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + List
articles = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(new ParameterizedTypeReference<>() {}); + + assertThat(articles).isEqualTo(List.of(article)); + } + + @Test + void shouldPostAndPutAndGetArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + Article articleChanged = new Article(1, "How to use RestClient even better"); + restClient.put() + .uri(uriBase + "/articles/1") + .contentType(MediaType.APPLICATION_JSON) + .body(articleChanged) + .retrieve() + .toBodilessEntity(); + + List
articles = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(new ParameterizedTypeReference<>() {}); + + assertThat(articles).isEqualTo(List.of(articleChanged)); + } + + @Test + void shouldPostAndDeleteArticles() { + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + restClient.delete() + .uri(uriBase + "/articles") + .retrieve() + .toBodilessEntity(); + + List
articles = restClient.get() + .uri(uriBase + "/articles") + .retrieve() + .body(new ParameterizedTypeReference<>() {}); + + assertThat(articles).isEqualTo(List.of()); + } +} From dc512cc40884797493388ae181956f80a0c40452 Mon Sep 17 00:00:00 2001 From: Alexandru Borza Date: Mon, 2 Oct 2023 16:09:22 +0300 Subject: [PATCH 083/135] BAEL-6971 Unnamed Classes and Instance Main Methods in Java 21 (#14841) * BAEL-6727 Streams vs. Loops in Java * BAEL-6971 - Unnamed Classes and Instance Main Methods in Java 21 * BAEL-6971 - decomment code * BAEL-6971 - add child class * BAEL-6971 - add unnamed class with method --- .../main/java/com/baeldung/unnamedclasses/HelloWorld.java | 3 +++ .../java/com/baeldung/unnamedclasses/HelloWorldChild.java | 7 +++++++ .../java/com/baeldung/unnamedclasses/HelloWorldSuper.java | 7 +++++++ .../com/baeldung/unnamedclasses/HelloWorldWithMethod.java | 6 ++++++ 4 files changed, 23 insertions(+) create mode 100644 core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java create mode 100644 core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java create mode 100644 core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java create mode 100644 core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java new file mode 100644 index 0000000000..bf0e2c96c2 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java @@ -0,0 +1,3 @@ +void main() { + System.out.println("Hello, World!"); +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java new file mode 100644 index 0000000000..827be7c788 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldChild extends HelloWorldSuper { + void main() { + System.out.println("Hello, World!"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java new file mode 100644 index 0000000000..59c88716a4 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldSuper { + public static void main(String[] args) { + System.out.println("Hello from the superclass"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java new file mode 100644 index 0000000000..698516544e --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java @@ -0,0 +1,6 @@ +private String getMessage() { + return "Hello, World!"; +} +void main() { + System.out.println(getMessage()); +} From 99437e5c52683d001cbc8e943a24180e42eaf441 Mon Sep 17 00:00:00 2001 From: Kasra Madadipouya Date: Mon, 2 Oct 2023 19:07:03 +0200 Subject: [PATCH 084/135] JAVA-25344 fix spring-data-cassandra-2 tests (#14799) --- .../ProductRepositoryNestedLiveTest.java | 2 +- .../baeldung/objectmapper/MapperLiveTest.java | 52 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java index 3d2433814e..3592c8b80d 100644 --- a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java @@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.*; @Testcontainers @SpringBootTest -class ProductRepositoryIntegrationTest { +class ProductRepositoryNestedLiveTest { private static final String KEYSPACE_NAME = "mynamespace"; diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java index b61663d622..50681d36c5 100644 --- a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java @@ -1,7 +1,8 @@ package org.baeldung.objectmapper; -import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.api.core.CqlSession; +import java.net.InetSocketAddress; +import java.util.List; + import org.baeldung.objectmapper.dao.CounterDao; import org.baeldung.objectmapper.dao.UserDao; import org.baeldung.objectmapper.entity.Counter; @@ -14,7 +15,8 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.List; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; @Testcontainers @SpringBootTest @@ -23,35 +25,30 @@ public class MapperLiveTest { private static final String KEYSPACE_NAME = "baeldung"; @Container - private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2") - .withExposedPorts(9042); + private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2").withExposedPorts(9042); + @BeforeAll static void setupCassandraConnectionProperties() { System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME); - System.setProperty("spring.data.cassandra.contact-points", cassandra.getContainerIpAddress()); + System.setProperty("spring.data.cassandra.contact-points", cassandra.getHost()); System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042))); + setupCassandra(new InetSocketAddress(cassandra.getHost(), cassandra.getMappedPort(9042)), cassandra.getLocalDatacenter()); } static UserDao userDao; static CounterDao counterDao; - @BeforeAll - static void setup() { - setupCassandraConnectionProperties(); - CqlSession session = CqlSession.builder().build(); + static void setupCassandra(InetSocketAddress cassandraEndpoint, String localDataCenter) { + CqlSession session = CqlSession.builder() + .withLocalDatacenter(localDataCenter) + .addContactPoint(cassandraEndpoint) + .build(); - String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + - "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; + String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; String useKeyspace = "USE baeldung;"; - String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + - "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + - "(id int, username text, user_age int, role text, writetime bigint, department text, " + - "PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createCounter = "CREATE TABLE IF NOT EXISTS counter " + - "(id text, count counter, PRIMARY KEY (id));"; + String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + "(id int, username text, user_age int, role text, writetime bigint, department text, " + "PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createCounter = "CREATE TABLE IF NOT EXISTS counter " + "(id text, count counter, PRIMARY KEY (id));"; session.execute(createKeyspace); session.execute(useKeyspace); @@ -75,22 +72,25 @@ public class MapperLiveTest { @Test void givenCounter_whenIncrement_thenIncremented() { Counter users = counterDao.getCounterById("users"); - long initialCount = users != null ? users.getCount(): 0; + long initialCount = users != null ? users.getCount() : 0; counterDao.incrementCounter("users", 1); users = counterDao.getCounterById("users"); - long finalCount = users != null ? users.getCount(): 0; + long finalCount = users != null ? users.getCount() : 0; Assertions.assertEquals(finalCount - initialCount, 1); } @Test void givenUser_whenGetUsersOlderThan_thenRetrieved() { - User user = new User(2, "JaneDoe", 20); + User user = new User(2, "JaneDoe", 32); + User userTwo = new User(3, "JohnDoe", 20); userDao.insertUser(user); - List retrievedUsers = userDao.getUsersOlderThanAge(30).all(); - Assertions.assertEquals(retrievedUsers.size(), 1); + userDao.insertUser(userTwo); + List retrievedUsers = userDao.getUsersOlderThanAge(30) + .all(); + Assertions.assertEquals(1, retrievedUsers.size()); } } \ No newline at end of file From 40c5ed0c6f6ff9e8f0588a6b31e2e9239a0b612c Mon Sep 17 00:00:00 2001 From: anuragkumawat Date: Mon, 2 Oct 2023 23:07:36 +0530 Subject: [PATCH 085/135] JAVA-24378 Fix references to parents - Week 35 - 2023 (#14852) --- jenkins-modules/plugins/pom.xml | 1 + spring-boot-modules/spring-boot-keycloak-2/pom.xml | 7 +++---- spring-boot-modules/spring-boot-keycloak-adapters/pom.xml | 7 +++---- spring-boot-modules/spring-boot-keycloak/pom.xml | 7 +++---- spring-boot-modules/spring-boot-logging-log4j2/pom.xml | 7 +++---- spring-boot-modules/spring-boot-mvc-birt/pom.xml | 7 +++---- spring-boot-modules/spring-boot-ssl-bundles/pom.xml | 8 ++++---- ...BundleApplicationTests.java => SpringContextTest.java} | 2 +- 8 files changed, 21 insertions(+), 25 deletions(-) rename spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/{SSLBundleApplicationTests.java => SpringContextTest.java} (85%) diff --git a/jenkins-modules/plugins/pom.xml b/jenkins-modules/plugins/pom.xml index 42add1664e..c2b1408556 100644 --- a/jenkins-modules/plugins/pom.xml +++ b/jenkins-modules/plugins/pom.xml @@ -12,6 +12,7 @@ org.jenkins-ci.plugins plugin 2.33 + diff --git a/spring-boot-modules/spring-boot-keycloak-2/pom.xml b/spring-boot-modules/spring-boot-keycloak-2/pom.xml index 39a7283328..7909e2e153 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-2/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml index 035c226b6d..34c0653fbd 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index 64fb39d085..bada9ab52d 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml index b429339417..31c0f4bd02 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml @@ -9,10 +9,9 @@ Demo project for Spring Boot Logging with Log4J2 - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-mvc-birt/pom.xml b/spring-boot-modules/spring-boot-mvc-birt/pom.xml index 274932f06c..cc4b7f8283 100644 --- a/spring-boot-modules/spring-boot-mvc-birt/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-birt/pom.xml @@ -10,10 +10,9 @@ Module For Spring Boot Integration with BIRT - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml index 056d0308c2..4802e9ec58 100644 --- a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml +++ b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml @@ -4,10 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.1.3 - + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 springbootsslbundles spring-boot-ssl-bundles diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java similarity index 85% rename from spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java rename to spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java index 876641c8b5..6c9a2fb3f0 100644 --- a/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class SSLBundleApplicationTests { +class SpringContextTest { @Test void contextLoads() { From b52e2cc3d1ac74468b8c808b63c0223a45a7f048 Mon Sep 17 00:00:00 2001 From: Somnath Musib <7885767+musibs@users.noreply.github.com> Date: Tue, 3 Oct 2023 01:07:18 +0300 Subject: [PATCH 086/135] BAEL-6527 GraalVM Native Image Docker Image (#14835) * BAEL-6527 GraalVM Native Image Docker Image * BAEL-6527 GraalVM Native Image Docker Image --- spring-boot-modules/pom.xml | 1 + .../spring-boot-graalvm-docker/Dockerfile | 3 ++ .../spring-boot-graalvm-docker/pom.xml | 41 +++++++++++++++++++ .../GraalvmDockerImageApplication.java | 24 +++++++++++ .../src/main/resources/application.properties | 1 + 5 files changed, 70 insertions(+) create mode 100644 spring-boot-modules/spring-boot-graalvm-docker/Dockerfile create mode 100644 spring-boot-modules/spring-boot-graalvm-docker/pom.xml create mode 100644 spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java create mode 100644 spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 1c4b2bb38f..2b4a94a7a5 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -104,6 +104,7 @@ spring-boot-springdoc-2 spring-boot-documentation spring-boot-3-url-matching + spring-boot-graalvm-docker diff --git a/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile new file mode 100644 index 0000000000..91a63074c1 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile @@ -0,0 +1,3 @@ +FROM ubuntu:jammy +COPY target/springboot-graalvm-docker /springboot-graalvm-docker +CMD ["/springboot-graalvm-docker"] diff --git a/spring-boot-modules/spring-boot-graalvm-docker/pom.xml b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml new file mode 100644 index 0000000000..a3a1b148c2 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + com.baeldung + spring-boot-graalvm-docker + 1.0.0 + spring-boot-graalvm-docker + Spring Boot GrralVM with Docker + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java new file mode 100644 index 0000000000..53e11aa749 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.graalvmdockerimage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class GraalvmDockerImageApplication { + + public static void main(String[] args) { + SpringApplication.run(GraalvmDockerImageApplication.class, args); + } + +} + +@RestController +class HelloController { + + @GetMapping + public String hello() { + return "Hello GraalVM"; + } +} diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties @@ -0,0 +1 @@ + From e331611860dda4255686b440b8afb3cb0a93ce85 Mon Sep 17 00:00:00 2001 From: timis1 <12120641+timis1@users.noreply.github.com> Date: Tue, 3 Oct 2023 07:17:04 +0300 Subject: [PATCH 087/135] JAVA-24463 Fixing Failed tests from spring-5-reactive (#14881) Co-authored-by: timis1 --- .../baeldung/reactive/controller/PathPatternController.java | 4 ++-- .../ExploreSpring5URLPatternUsingRouterFunctions.java | 2 +- ...eSpring5URLPatternUsingRouterFunctionsIntegrationTest.java | 4 ++-- .../PathPatternsUsingHandlerMethodIntegrationTest.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java index 653c95d566..3c9cb812f2 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java @@ -22,9 +22,9 @@ public class PathPatternController { return "/spring5/*id"; } - @GetMapping("//**") + @GetMapping("/resources/**") public String wildcardTakingZeroOrMorePathSegments() { - return "//**"; + return "/resources/**"; } @GetMapping("/{baeldung:[a-z]+}") diff --git a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java index 60cf85e5da..b7bb53600e 100644 --- a/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java @@ -29,7 +29,7 @@ public class ExploreSpring5URLPatternUsingRouterFunctions { .andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2")))) .andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromValue("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung")))) .and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/"))) - .and(RouterFunctions.resources("//**", new ClassPathResource("/"))); + .and(RouterFunctions.resources("/resources/**", new ClassPathResource("resources/"))); } WebServer start() throws Exception { diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java index 63dfbd44a1..113376318e 100644 --- a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java +++ b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java @@ -108,9 +108,9 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { } @Test - public void givenRouter_whenAccess_thenGot() throws Exception { + public void givenRouter_whenAccess_thenGot() { client.get() - .uri("//test/test.txt") + .uri("/resources/test/test.txt") .exchange() .expectStatus() .isOk() diff --git a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java index 8eb8d04cd4..0b4607b54a 100644 --- a/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java +++ b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java @@ -72,12 +72,12 @@ public class PathPatternsUsingHandlerMethodIntegrationTest { public void givenHandlerMethod_whenURLWithWildcardTakingZeroOrMorePathSegments_then200() { client.get() - .uri("//baeldung") + .uri("/resources/baeldung") .exchange() .expectStatus() .is2xxSuccessful() .expectBody() - .equals("//**"); + .equals("/resources/**"); } @Test From ca1590cc663ce1c164ee6f66efd06a9438d56ec1 Mon Sep 17 00:00:00 2001 From: timis1 <12120641+timis1@users.noreply.github.com> Date: Tue, 3 Oct 2023 07:25:06 +0300 Subject: [PATCH 088/135] JAVA-25542 Check code of spring-reactive ebook (#14880) Co-authored-by: timis1 --- spring-reactive-modules/spring-reactive-exceptions/README.md | 3 +-- spring-reactive-modules/spring-reactive/README.md | 1 + spring-reactive-modules/spring-reactive/pom.xml | 2 +- .../reactive/errorhandling/ErrorHandlingApplication.java | 2 +- .../reactive/errorhandling/GlobalErrorAttributes.java | 2 +- .../reactive/errorhandling/GlobalErrorWebExceptionHandler.java | 2 +- .../java/com/baeldung}/reactive/errorhandling/Handler.java | 2 +- .../reactive/errorhandling/NameRequiredException.java | 2 +- .../main/java/com/baeldung}/reactive/errorhandling/Router.java | 2 +- .../reactive/errorhandling/ErrorHandlingIntegrationTest.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/ErrorHandlingApplication.java (93%) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/GlobalErrorAttributes.java (93%) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/GlobalErrorWebExceptionHandler.java (97%) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/Handler.java (97%) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/NameRequiredException.java (85%) rename spring-reactive-modules/{spring-reactive-exceptions/src/main/java/com/baeldung/spring => spring-reactive/src/main/java/com/baeldung}/reactive/errorhandling/Router.java (96%) rename spring-reactive-modules/{spring-reactive-exceptions/src/test/java/com/baeldung/spring => spring-reactive/src/test/java/com/baeldung}/reactive/errorhandling/ErrorHandlingIntegrationTest.java (98%) diff --git a/spring-reactive-modules/spring-reactive-exceptions/README.md b/spring-reactive-modules/spring-reactive-exceptions/README.md index f7e2c8cae0..f10774d188 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/README.md +++ b/spring-reactive-modules/spring-reactive-exceptions/README.md @@ -1,4 +1,3 @@ ## Relevant Articles - [How to Resolve Spring Webflux DataBufferLimitException](https://www.baeldung.com/spring-webflux-databufferlimitexception) -- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) -- [Handling Errors in Spring WebFlux](https://www.baeldung.com/spring-webflux-errors) \ No newline at end of file +- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive/README.md b/spring-reactive-modules/spring-reactive/README.md index 5e52212061..2b707a5d4e 100644 --- a/spring-reactive-modules/spring-reactive/README.md +++ b/spring-reactive-modules/spring-reactive/README.md @@ -14,6 +14,7 @@ This module contains articles describing reactive processing in Spring. - [Spring 5 WebClient](https://www.baeldung.com/spring-5-webclient) - [Spring WebClient vs. RestTemplate](https://www.baeldung.com/spring-webclient-resttemplate) - [Spring WebClient Requests with Parameters](https://www.baeldung.com/webflux-webclient-parameters) +- [Handling Errors in Spring WebFlux](https://www.baeldung.com/spring-webflux-errors) - [Spring Security 5 for Reactive Applications](https://www.baeldung.com/spring-security-5-reactive) - [Concurrency in Spring WebFlux](https://www.baeldung.com/spring-webflux-concurrency) diff --git a/spring-reactive-modules/spring-reactive/pom.xml b/spring-reactive-modules/spring-reactive/pom.xml index 263f29f9b5..f19809e302 100644 --- a/spring-reactive-modules/spring-reactive/pom.xml +++ b/spring-reactive-modules/spring-reactive/pom.xml @@ -9,7 +9,7 @@ com.baeldung parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-3/pom.xml + ../../parent-boot-3 diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java similarity index 93% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java index c34f86febd..50579d8721 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java similarity index 93% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java index 9dce1b3e5b..549ae749f2 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import java.util.Map; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java similarity index 97% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java index bfd3bba2a1..69f9a0420e 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import java.util.Map; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java similarity index 97% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java index 2956cc1686..f9e4ee4c35 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java similarity index 85% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java index 1926d6416a..bdc7771b80 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java similarity index 96% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java index c65b645f09..aeea202c31 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import static org.springframework.http.MediaType.TEXT_PLAIN; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java similarity index 98% rename from spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java index 972eefa5ac..0068379d61 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; From 7e8f6ef9c4ad6c0295c2a5c2f8a856c01b7adf4e Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Tue, 3 Oct 2023 09:56:28 +0530 Subject: [PATCH 089/135] Update README.md (#14894) --- spring-reactive-modules/spring-reactive/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-reactive-modules/spring-reactive/README.md b/spring-reactive-modules/spring-reactive/README.md index 2b707a5d4e..61d781b312 100644 --- a/spring-reactive-modules/spring-reactive/README.md +++ b/spring-reactive-modules/spring-reactive/README.md @@ -1,5 +1,5 @@ -This module contains articles about Spring Reactive that are also part of an Ebook. +This module contains articles about Spring Reactive that **are also part of an Ebook.** ## Spring Reactive @@ -20,4 +20,4 @@ This module contains articles describing reactive processing in Spring. ### NOTE: -Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. \ No newline at end of file +## Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. From 6f085f068a1874b555f971b2109ff88ad78c07e6 Mon Sep 17 00:00:00 2001 From: mcasari Date: Tue, 3 Oct 2023 18:34:40 +0200 Subject: [PATCH 090/135] BAEL-6846 - minor code format fix --- .../floattobigdecimal/FloatToBigDecimalUnitTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index 8895c01575..fe5dc360e4 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -44,10 +44,8 @@ class FloatToBigDecimalUnitTest { @Test public void whenCreatedByValueOf_thenFloatValueGetsTruncated() { - assertEquals("1.100000023841858", BigDecimal.valueOf(1.1f) - .toString()); - assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f) - .toString()); + assertEquals("1.100000023841858", BigDecimal.valueOf(1.1f).toString()); + assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f).toString()); } @Test From 3ecaaaec2827f2b06473d578ae8415faf228d029 Mon Sep 17 00:00:00 2001 From: Thiago dos Santos Hora Date: Tue, 3 Oct 2023 22:33:24 +0200 Subject: [PATCH 091/135] Bael 6917/api versioning micronaut (#14868) * BAEL-6917: Micronaut API Versioning * Fix test names --- microservices-modules/micronaut/pom.xml | 163 ++++++++++-------- .../custom/client/BirdCountClient.java | 42 +++++ .../custom/server/BirdCountController.java | 36 ++++ .../custom/server/CustomVersionResolver.java | 31 ++++ .../header/client/DogCountClient.java | 42 +++++ .../header/server/DogCountController.java | 36 ++++ .../param/client/CatCountClient.java | 23 +++ .../param/server/CatCountController.java | 37 ++++ .../url/client/SheepCountClient.java | 39 +++++ .../url/server/SheepCountControllerV1.java | 26 +++ .../url/server/SheepCountControllerV2.java | 27 +++ .../client/ConcreteGreetingClient.java | 15 +- .../controller/AsyncGreetController.java | 4 +- .../server/controller/GreetController.java | 2 +- .../service/EnglishGreetingService.java | 2 +- .../service/SpanishGreetingService.java | 2 +- .../vs/springboot/CompareApplication.java | 6 +- .../client/ArithmeticClientImpl.java | 30 ++-- .../controller/ArithmeticController.java | 2 +- .../springboot/service/ArithmeticService.java | 2 +- .../src/main/resources/application.yml | 22 ++- .../micronaut/src/main/resources/logback.xml | 6 + .../client/BirdCountClientUnitTest.java | 42 +++++ .../header/client/DogCountClientUnitTest.java | 40 +++++ .../param/client/CatCountClientUnitTest.java | 38 ++++ .../url/client/SheepCountClientUnitTest.java | 44 +++++ .../ConcreteGreetingClientUnitTest.java | 32 ++-- .../client/GreetingClientUnitTest.java | 31 ++-- .../springboot/ArithmeticClientUnitTest.java | 37 ++-- 29 files changed, 683 insertions(+), 176 deletions(-) create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java create mode 100644 microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java create mode 100644 microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java create mode 100644 microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java create mode 100644 microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java create mode 100644 microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java diff --git a/microservices-modules/micronaut/pom.xml b/microservices-modules/micronaut/pom.xml index 716b5497d8..d3f4326a85 100644 --- a/microservices-modules/micronaut/pom.xml +++ b/microservices-modules/micronaut/pom.xml @@ -7,6 +7,7 @@ micronaut 0.1 micronaut + ${packaging} com.baeldung @@ -18,7 +19,7 @@ io.micronaut - bom + micronaut-bom ${micronaut.version} pom import @@ -29,120 +30,136 @@ io.micronaut - http-client + micronaut-runtime + compile + + + io.micronaut + micronaut-jackson-databind + + + + + io.micronaut + micronaut-http-client compile io.micronaut - http-server-netty + micronaut-http-server-netty + compile + + + jakarta.annotation + jakarta.annotation-api compile io.micronaut - inject + micronaut-inject compile io.micronaut - runtime + micronaut-validation compile - - javax.annotation - javax.annotation-api - ${annotation.api.version} - compile - - - io.micronaut - inject-java - provided - ch.qos.logback logback-classic - ${logback.version} runtime - io.projectreactor - reactor-core - ${reactor.version} + io.micronaut.rxjava3 + micronaut-rxjava3 + compile + + + io.micronaut.rxjava3 + micronaut-rxjava3-http-client + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.assertj + assertj-core + test + + + io.micronaut.test + micronaut-test-junit5 + test + + io.micronaut.build + micronaut-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + ${jdk.version} + ${jdk.version} + + -parameters + + + + + + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + + io.micronaut + micronaut-http-validation + ${micronaut.version} + + + + + org.apache.maven.plugins maven-shade-plugin ${shade.plugin.version} - package - - shade - - - - - ${exec.mainClass} - - - - + default-shade + none - - org.codehaus.mojo - exec-maven-plugin - - java - - -classpath - - ${exec.mainClass} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler.plugin.version} - - ${jdk.version} - ${jdk.version} - - -parameters - - - - io.micronaut - inject-java - ${micronaut.version} - - - - - - com.baeldung.micronaut.vs.springboot.CompareApplication - 1.0.0.RC2 + 3.10.1 17 - 1.3.2 - 3.1.6.RELEASE + 17 + jar 3.7.0 - 3.1.0 + netty + 3.2.0 \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java new file mode 100644 index 0000000000..d9e09b1c6e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface BirdCountClient { + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "11") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "10") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "") + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java new file mode 100644 index 0000000000..c836761266 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/bird") +public class BirdCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java new file mode 100644 index 0000000000..3075a135c8 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java @@ -0,0 +1,31 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.annotation.Value; +import io.micronaut.http.HttpRequest; +import io.micronaut.web.router.version.resolution.RequestVersionResolver; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.Optional; + +@Singleton +@Requires(property = "my.router.versioning.enabled", value = "true") +public class CustomVersionResolver implements RequestVersionResolver { + + @Inject + @Value("${micronaut.router.versioning.default-version}") + private String defaultVersion; + + @Override + public Optional resolve(HttpRequest request) { + var apiKey = Optional.ofNullable(request.getHeaders().get("api-key")); + + if (apiKey.isPresent() && !apiKey.get().isEmpty()) { + return Optional.of(Integer.parseInt(apiKey.get()) % 2 == 0 ? "2" : "1"); + } + + return Optional.of(defaultVersion); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java new file mode 100644 index 0000000000..487bff4d57 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface DogCountClient { + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("1") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("2") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java new file mode 100644 index 0000000000..de0f6788cf --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.header.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/dog") +public class DogCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java new file mode 100644 index 0000000000..2332ade98e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java @@ -0,0 +1,23 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface CatCountClient { + + @Get( + uri = "/cat/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable count(@QueryValue("max") @Nullable Integer max, @QueryValue(value = "v", defaultValue = "1") @Nullable Integer version); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java new file mode 100644 index 0000000000..43a34a2272 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java @@ -0,0 +1,37 @@ +package com.baeldung.micronaut.apiversioning.param.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/cat") +public class CatCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max == null ? 10 : max) + ); + } + + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java new file mode 100644 index 0000000000..cdb344b4e5 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java @@ -0,0 +1,39 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface SheepCountClient { + + @Get( + uri = "/v1/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/v2/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java new file mode 100644 index 0000000000..5ee6a2a57d --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java @@ -0,0 +1,26 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/v1/sheep/count") +public class SheepCountControllerV1 { + + @Get( + uri = "{?max}", + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV1(@Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max == null ? 10 : max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java new file mode 100644 index 0000000000..d95f4a3cca --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java @@ -0,0 +1,27 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller +public class SheepCountControllerV2 { + + @Get( + uris = {"/v2/sheep/count", "/sheep/count"}, + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java index 96bc51f235..943b2f703e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java @@ -1,28 +1,27 @@ package com.baeldung.micronaut.helloworld.client; import io.micronaut.http.HttpRequest; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; -import io.micronaut.http.client.RxHttpClient; -import io.reactivex.Single; - -import javax.inject.Singleton; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ConcreteGreetingClient { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { + public ConcreteGreetingClient(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest req = HttpRequest.GET("/greet/" + name); - return httpClient.retrieve(req).blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)).blockingGet(); } public Single greetAsync(String name) { HttpRequest req = HttpRequest.GET("/async/greet/" + name); - return httpClient.retrieve(req).first("An error as occurred"); + return Single.fromPublisher(httpClient.retrieve(req)); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java index 4d86b9dfed..862a822573 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java @@ -3,9 +3,9 @@ package com.baeldung.micronaut.helloworld.server.controller; import com.baeldung.micronaut.helloworld.server.service.GreetingService; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; -import io.reactivex.Single; -import javax.inject.Inject; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Inject; @Controller("/async/greet") public class AsyncGreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java index c890c037e4..ba3b6197d8 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java @@ -7,7 +7,7 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Post; -import javax.inject.Inject; +import jakarta.inject.Inject; @Controller("/greet") public class GreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java index 8ea5172cf6..865ee0b639 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java @@ -2,7 +2,7 @@ package com.baeldung.micronaut.helloworld.server.service; import io.micronaut.context.annotation.Primary; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Primary @Singleton diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java index 1ec53d8b2d..e426c2911e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.helloworld.server.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class SpanishGreetingService implements GreetingService { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java index 4654526b28..0fea9f970b 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java @@ -1,9 +1,11 @@ package com.baeldung.micronaut.vs.springboot; + import io.micronaut.runtime.Micronaut; public class CompareApplication { + public static void main(String[] args) { - Micronaut.run(CompareApplication.class); + Micronaut.run(CompareApplication.class, args); } -} +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java index 6b7ae900be..95e3157bfe 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java @@ -1,46 +1,46 @@ package com.baeldung.micronaut.vs.springboot.client; -import javax.inject.Singleton; - import io.micronaut.http.HttpRequest; -import io.micronaut.http.client.RxHttpClient; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ArithmeticClientImpl { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ArithmeticClientImpl(@Client("/") RxHttpClient httpClient) { + public ArithmeticClientImpl(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String sum(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/sum/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String subtract(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/subtract/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String multiply(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/multiply/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String divide(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/divide/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String memory() { HttpRequest req = HttpRequest.GET("/math/memory"); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java index 5bc0e865e1..b774556ece 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java @@ -3,7 +3,7 @@ package com.baeldung.micronaut.vs.springboot.controller; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; -import javax.inject.Inject; +import jakarta.inject.Inject; import com.baeldung.micronaut.vs.springboot.service.ArithmeticService; diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java index e0e4680495..599a6ee4cf 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.vs.springboot.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class ArithmeticService { diff --git a/microservices-modules/micronaut/src/main/resources/application.yml b/microservices-modules/micronaut/src/main/resources/application.yml index 32daacd4aa..b265d245aa 100644 --- a/microservices-modules/micronaut/src/main/resources/application.yml +++ b/microservices-modules/micronaut/src/main/resources/application.yml @@ -1,5 +1,19 @@ +context-path: / + micronaut: - application: - name: hello-world-server - server: - port: ${random.port} \ No newline at end of file + router: + versioning: + enabled: true + default-version: 2 + parameter: + enabled: true + names: 'v,api-version' + header: + enabled: true + names: + - 'X-API-VERSION' + + application: + name: hello-world-server + server: + port: ${random.port} diff --git a/microservices-modules/micronaut/src/main/resources/logback.xml b/microservices-modules/micronaut/src/main/resources/logback.xml index afaebf8e17..4db42a7916 100644 --- a/microservices-modules/micronaut/src/main/resources/logback.xml +++ b/microservices-modules/micronaut/src/main/resources/logback.xml @@ -8,6 +8,12 @@ + + + diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java new file mode 100644 index 0000000000..a3a547f9e2 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.context.annotation.Property; +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +@Property(name = "my.router.versioning.enabled", value = "true") +class BirdCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private BirdCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java new file mode 100644 index 0000000000..4a47c76943 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class DogCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private DogCountClient dogCountClient; + + @Test + void givenTheCountApi_whenUsingV1ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, dogCountClient.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, dogCountClient.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java new file mode 100644 index 0000000000..266f72eed8 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class CatCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private CatCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, 1).blockingSingle().split(",").length); + Assertions.assertEquals(5, client.count(5, 1).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.count(null, 2).count().blockingGet()); + + Assertions.assertEquals(6, client.count(6, 2).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, null).blockingSingle().split(",").length); + Assertions.assertEquals(6, client.count(6, null).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java new file mode 100644 index 0000000000..e082793fe1 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.stream.Collectors; + +@MicronautTest +class SheepCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + @Inject + private SheepCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + final var actual = client.countV2(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + final var actual = client.countDefault(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java index 336374d5a6..88a9782074 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java @@ -1,31 +1,19 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class ConcreteGreetingClientUnitTest -{ - private EmbeddedServer server; +@MicronautTest +public class ConcreteGreetingClientUnitTest { + @Inject + private EmbeddedApplication application; + @Inject private ConcreteGreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(ConcreteGreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java index c47fb3a31d..5b269531e7 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java @@ -1,30 +1,21 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +@MicronautTest public class GreetingClientUnitTest { - private EmbeddedServer server; + + @Inject + private EmbeddedApplication application; + + @Inject private GreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(GreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java index 9a1b095d22..fa191778f5 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java @@ -1,34 +1,21 @@ package com.baeldung.micronaut.vs.springboot; -import static org.junit.Assert.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import com.baeldung.micronaut.vs.springboot.client.ArithmeticClientImpl; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest public class ArithmeticClientUnitTest { - private EmbeddedServer server; + @Inject + private EmbeddedApplication server; + @Inject private ArithmeticClientImpl client; - @Before - public void setup() { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext() - .getBean(ArithmeticClientImpl.class); - } - - @After - public void cleanup() { - server.stop(); - } - @Test public void givenTwoNumbers_whenAdd_thenCorrectAnswerReturned() { String expected = Float.valueOf(10 + 20).toString(); @@ -56,6 +43,6 @@ public class ArithmeticClientUnitTest { @Test public void whenMemory_thenCorrectAnswerReturned() { String expected = "Initial:"; - assertThat(client.memory(), containsString(expected)); + assertThat(client.memory()).contains(expected); } } From 7e1d5991e61a969ec922f5a7182096ee76002d0f Mon Sep 17 00:00:00 2001 From: mcasari Date: Tue, 3 Oct 2023 23:41:11 +0200 Subject: [PATCH 092/135] BAEL-6846 - tests revision due to article updates --- .../FloatToBigDecimalUnitTest.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index fe5dc360e4..9d125f557d 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -17,40 +17,32 @@ class FloatToBigDecimalUnitTest { @Test public void whenCreatedFromFloat_thenMatchesInternallyStoredValue() { - float floatToConvert = 1.1f; + float floatToConvert = 1.10000002384185791015625f; BigDecimal bdFromFloat = new BigDecimal(floatToConvert); assertEquals("1.10000002384185791015625", bdFromFloat.toString()); } @Test public void whenCreatedFromString_thenPreservesTheOriginal() { - BigDecimal bdFromString = new BigDecimal("1.1"); - assertEquals("1.1", bdFromString.toString()); + BigDecimal bdFromString = new BigDecimal("1.10000002384185791015625"); + assertEquals("1.10000002384185791015625", bdFromString.toString()); } @Test public void whenCreatedFromFloatConvertedToString_thenFloatInternalValueGetsTruncated() { - String floatValue = Float.toString(1.1f); + String floatValue = Float.toString(1.10000002384185791015625f); BigDecimal bdFromString = new BigDecimal(floatValue); assertEquals("1.1", floatValue); assertEquals("1.1", bdFromString.toString()); } - @Test - public void whenFloatConvertedToString_thenGetsTruncated() { - String floatValue = Float.toString(1.10000002384185791015625f); - assertEquals("1.1", floatValue); - } - @Test public void whenCreatedByValueOf_thenFloatValueGetsTruncated() { - assertEquals("1.100000023841858", BigDecimal.valueOf(1.1f).toString()); assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f).toString()); } @Test public void whenDoubleConvertsFloatToString_thenFloatValueGetsTruncated() { - assertEquals("1.100000023841858", Double.toString(1.1f)); assertEquals("1.100000023841858", Double.toString(1.10000002384185791015625f)); } From d76083ae0473e78f515f1c48d374eb7cb0c04f14 Mon Sep 17 00:00:00 2001 From: Eugene Kovko <37694937+eukovko@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:23:38 +0200 Subject: [PATCH 093/135] BAEL-6828: Finding the Square Root of a BigInteger in Java (#14903) * BAEL-6828: Finding the Square Root of a BigInteger in Java * BAEL-6828: Remove Java 9 annotation from the test * BAEL-6828: Remove Java 9 profile --- core-java-modules/core-java-numbers-6/pom.xml | 7 +- .../bigintegerroot/BenchmarkRunner.java | 8 ++ .../bigintegerroot/BigIntegerHolder.java | 10 ++ .../BigIntegerSquareRootBenchmark.java | 60 ++++++++++ .../bigintegerroot/algorithms/Newton.java | 29 +++++ .../bigintegerroot/algorithms/NewtonPlus.java | 108 ++++++++++++++++++ .../BigIntegerSquareRootUnitTest.java | 39 +++++++ 7 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java create mode 100644 core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java create mode 100644 core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java create mode 100644 core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java create mode 100644 core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java create mode 100644 core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java diff --git a/core-java-modules/core-java-numbers-6/pom.xml b/core-java-modules/core-java-numbers-6/pom.xml index 531f1293d1..7a3b3d4426 100644 --- a/core-java-modules/core-java-numbers-6/pom.xml +++ b/core-java-modules/core-java-numbers-6/pom.xml @@ -25,8 +25,12 @@ ${commons-codec} test + + com.google.guava + guava + ${guava.version} + - core-java-numbers-6 @@ -39,5 +43,6 @@ 1.15 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java new file mode 100644 index 0000000000..2ac57a9c0c --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java @@ -0,0 +1,8 @@ +package com.baeldung.bigintegerroot; + +public class BenchmarkRunner { + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +} + diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java new file mode 100644 index 0000000000..c2d2f30827 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java @@ -0,0 +1,10 @@ +package com.baeldung.bigintegerroot; + +public class BigIntegerHolder { + + private BigIntegerHolder() { + } + public static final String BIG_NUMBER = "179769313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + public static final String VERY_BIG_NUMBER = "32473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; + public static final String INSANELY_BIG_NUMBER = "3247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java new file mode 100644 index 0000000000..645e4eb2dd --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java @@ -0,0 +1,60 @@ +package com.baeldung.bigintegerroot; + +import static com.baeldung.bigintegerroot.BigIntegerHolder.*; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1) +@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES) +@Fork(1) +@State(Scope.Benchmark) +public class BigIntegerSquareRootBenchmark { + + @Param({BIG_NUMBER, VERY_BIG_NUMBER, INSANELY_BIG_NUMBER}) + public String number; + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithJava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = integer.sqrt(); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithGuava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = BigIntegerMath.sqrt(integer, RoundingMode.DOWN); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewtonPlus(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = NewtonPlus.sqrt(integer); + blackhole.consume(root); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewton(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = Newton.sqrt(integer); + blackhole.consume(root); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java new file mode 100644 index 0000000000..07acba7537 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java @@ -0,0 +1,29 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class Newton { + + private Newton() { + } + + public static BigInteger sqrt(BigInteger n) { + // Initial approximation + BigInteger x = n.divide(BigInteger.TWO); + + // Tolerance level (small positive integer) + BigInteger tolerance = BigInteger.ONE; + + while (true) { + // x_new = 0.5 * (x + n / x) + BigInteger xNew = x.add(n.divide(x)).divide(BigInteger.TWO); + + // Check for convergence within tolerance + if (x.subtract(xNew).abs().compareTo(tolerance) <= 0) { + return xNew; + } + + x = xNew; + } + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java new file mode 100644 index 0000000000..80d50c0ca5 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java @@ -0,0 +1,108 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class NewtonPlus { + + private NewtonPlus() { + } + + // A fast square root by Ryan Scott White. + public static BigInteger sqrt(BigInteger x) { + if (x.compareTo(BigInteger.valueOf(144838757784765629L)) < 0) { + long xAsLong = x.longValue(); + long vInt = (long)Math.sqrt(xAsLong); + if (vInt * vInt > xAsLong) + vInt--; + return BigInteger.valueOf(vInt); } + + double xAsDub = x.doubleValue(); + BigInteger val; + if (xAsDub < 2.1267e37) // 2.12e37 largest here + // since sqrt(long.max*long.max) > long.max + { + long vInt = (long)Math.sqrt(xAsDub); + val = BigInteger.valueOf + ((vInt + x.divide(BigInteger.valueOf(vInt)).longValue()) >> 1); + } + else if (xAsDub < 4.3322e127) { + // Convert a double to a BigInteger + long bits = Double.doubleToLongBits(Math.sqrt(xAsDub)); + int exp = ((int) (bits >> 52) & 0x7ff) - 1075; + val = BigInteger.valueOf((bits & ((1L << 52)) - 1) | (1L << 52)).shiftLeft(exp); + + val = x.divide(val).add(val).shiftRight(1); + if (xAsDub > 2e63) { + val = x.divide(val).add(val).shiftRight(1); } + } + else // handle large numbers over 4.3322e127 + { + int xLen = x.bitLength(); + int wantedPrecision = ((xLen + 1) / 2); + int xLenMod = xLen + (xLen & 1) + 1; + + //////// Do the first Sqrt on Hardware //////// + long tempX = x.shiftRight(xLenMod - 63).longValue(); + double tempSqrt1 = Math.sqrt(tempX); + long valLong = Double.doubleToLongBits(tempSqrt1) & 0x1fffffffffffffL; + + if (valLong == 0) + valLong = 1L << 53; + + //////// Classic Newton Iterations //////// + val = BigInteger.valueOf(valLong).shiftLeft(53 - 1) + .add((x.shiftRight(xLenMod - + (3 * 53))).divide(BigInteger.valueOf(valLong))); + + int size = 106; + for (; size < 256; size <<= 1) { + val = val.shiftLeft(size - 1).add(x.shiftRight + (xLenMod - (3*size)).divide(val));} + + if (xAsDub > 4e254) { // 4e254 = 1<<845.77 + int numOfNewtonSteps = 31 - + Integer.numberOfLeadingZeros(wantedPrecision / size)+1; + + ////// Apply Starting Size //////// + int wantedSize = (wantedPrecision >> numOfNewtonSteps) + 2; + int needToShiftBy = size - wantedSize; + val = val.shiftRight(needToShiftBy); + + size = wantedSize; + do { + //////// Newton Plus Iteration //////// + int shiftX = xLenMod - (3 * size); + BigInteger valSqrd = val.multiply(val).shiftLeft(size - 1); + BigInteger valSU = x.shiftRight(shiftX).subtract(valSqrd); + val = val.shiftLeft(size).add(valSU.divide(val)); + size *= 2; + } while (size < wantedPrecision); + } + val = val.shiftRight(size - wantedPrecision); + } + + // Detect a round ups. This function can be further optimized - see article. + // For a ~7% speed bump the following line can be removed but round-ups will occur. + if (val.multiply(val).compareTo(x) > 0) + val = val.subtract(BigInteger.ONE); + + // Enabling the below will guarantee an error is stopped for larger numbers. + // Note: As of this writing, there are no known errors. + BigInteger tmp = val.multiply(val); + if (tmp.compareTo(x) > 0) { + System.out.println("val^2(" + val.multiply(val).toString() + + ") ≥ x(" + x.toString()+")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too high"); + } + if (tmp.add(val.shiftLeft(1)).add(BigInteger.ONE).compareTo(x) <= 0) { + System.out.println("(val+1)^2(" + + val.add(BigInteger.ONE).multiply(val.add(BigInteger.ONE)).toString() + + ") ≥ x(" + x.toString() + ")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too low"); + } + + return val; + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java new file mode 100644 index 0000000000..edb75b16ef --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.bigintegerroot; + + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.stream.Stream; +import org.apache.commons.math3.util.Pair; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BigIntegerSquareRootUnitTest { + + @ParameterizedTest + @ValueSource(strings = { + BigIntegerHolder.BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER + }) + void squareRootTest(String number) { + final BigInteger bigInteger = new BigInteger(number); + final BigInteger javaRoot = bigInteger.sqrt(); + final BigInteger guavaRoot = BigIntegerMath.sqrt(bigInteger, RoundingMode.DOWN); + final BigInteger newtonRoot = Newton.sqrt(bigInteger); + final BigInteger newtonPlusRoot = NewtonPlus.sqrt(bigInteger); + + assertTrue(Stream.of( + new Pair<>(javaRoot, guavaRoot), + new Pair<>(guavaRoot, newtonRoot), + new Pair<>(newtonRoot, newtonPlusRoot) + ).allMatch(pair -> pair.getFirst().equals(pair.getSecond()))); + } +} \ No newline at end of file From 0c0dddef88f18c80646e08a8420446a38f10a0b2 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:31:17 +0800 Subject: [PATCH 094/135] Update README.md [skip ci] --- core-java-modules/core-java-collections-conversions-3/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-collections-conversions-3/README.md b/core-java-modules/core-java-collections-conversions-3/README.md index f89cd199ff..653f518840 100644 --- a/core-java-modules/core-java-collections-conversions-3/README.md +++ b/core-java-modules/core-java-collections-conversions-3/README.md @@ -3,3 +3,4 @@ This module contains articles about conversions among Collection types in Java. ### Relevant Articles: +- [Converting HashMap Values to an ArrayList in Java](https://www.baeldung.com/java-hashmap-arraylist) From 39f1754fadb605c9d5c1ca1e1a3b5887ce269956 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:38:21 +0800 Subject: [PATCH 095/135] Update README.md [skip ci] --- core-java-modules/core-java-collections-5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-collections-5/README.md b/core-java-modules/core-java-collections-5/README.md index 1769d11686..b9fca9e584 100644 --- a/core-java-modules/core-java-collections-5/README.md +++ b/core-java-modules/core-java-collections-5/README.md @@ -5,4 +5,5 @@ ### Relevant Articles: - [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro) - [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator) +- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) From 5266e4d218535af94f98f47d948c92aca6295553 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:40:11 +0800 Subject: [PATCH 096/135] Update README.md [skip ci] --- core-java-modules/core-java-char/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-char/README.md b/core-java-modules/core-java-char/README.md index e4af3121c5..56040a3ea5 100644 --- a/core-java-modules/core-java-char/README.md +++ b/core-java-modules/core-java-char/README.md @@ -5,3 +5,4 @@ This module contains articles about Java Character Class ### Relevant Articles: - [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic) - [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string) +- [Increment Character in Java](https://www.baeldung.com/java-char-sequence) From de26c627a75dd0f366fa4e2df65b79b0d872521f Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:45:29 +0800 Subject: [PATCH 097/135] Update README.md [skip ci] --- apache-kafka-2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apache-kafka-2/README.md b/apache-kafka-2/README.md index dc675a0811..40ee701be1 100644 --- a/apache-kafka-2/README.md +++ b/apache-kafka-2/README.md @@ -13,3 +13,4 @@ You can build the project from the command line using: *mvn clean install*, or i - [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read) - [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) - [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server) +- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka) From cfcaee0e0194c9ff60964621f8093bff4ef05e48 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:49:25 +0800 Subject: [PATCH 098/135] Update README.md [skip ci] --- core-java-modules/core-java-os/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-os/README.md b/core-java-modules/core-java-os/README.md index 6d477de70a..81e67e4663 100644 --- a/core-java-modules/core-java-os/README.md +++ b/core-java-modules/core-java-os/README.md @@ -14,5 +14,6 @@ This module contains articles about working with the operating system (OS) in Ja - [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java) - [Taking Screenshots Using Java](https://www.baeldung.com/java-taking-screenshots) - [Java Sound API – Capturing Microphone](https://www.baeldung.com/java-sound-api-capture-mic) +- [How to Detect the Username Using Java](https://www.baeldung.com/java-get-username) This module uses Java 9, so make sure to have the JDK 9 installed to run it. From 7607c700b59ce668f9d8c44ddd75065e842f1109 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:52:15 +0800 Subject: [PATCH 099/135] Update README.md [skip ci] --- core-java-modules/core-java-collections-5/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-collections-5/README.md b/core-java-modules/core-java-collections-5/README.md index b9fca9e584..e478d87ad0 100644 --- a/core-java-modules/core-java-collections-5/README.md +++ b/core-java-modules/core-java-collections-5/README.md @@ -6,4 +6,5 @@ - [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro) - [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator) - [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods) +- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) From d9c845f3d277bcd7f96a788e27cee905821903ce Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:57:02 +0800 Subject: [PATCH 100/135] Update README.md [skip ci] --- core-java-modules/core-java-io-5/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-modules/core-java-io-5/README.md b/core-java-modules/core-java-io-5/README.md index 6072e0b6d9..9fb4b967a4 100644 --- a/core-java-modules/core-java-io-5/README.md +++ b/core-java-modules/core-java-io-5/README.md @@ -3,6 +3,6 @@ This module contains articles about core Java input and output (IO) ### Relevant Articles: - +- [Get File Extension From MIME Type in Java](https://www.baeldung.com/java-mime-type-file-extension) - [[<-- Prev]](/core-java-modules/core-java-io-4) From d79e840c9d7e59fecfb8d9cacb10502840b8e5f8 Mon Sep 17 00:00:00 2001 From: Bipin kumar Date: Thu, 5 Oct 2023 13:38:20 +0530 Subject: [PATCH 101/135] JAVA-25433: Fix the failing test in core-java-datetime-conversion (#14878) --- .../EpochTimeToLocalDateTimeConverterUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java index 6e3b250938..80c403bb4e 100644 --- a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java @@ -12,10 +12,10 @@ public class EpochTimeToLocalDateTimeConverterUnitTest { @Test public void testConvertEpochTimeToLocalDateTime() { long epochTimeMillis = 1624962431000L; // Example epoch time in milliseconds - LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 12, 13, 51); + LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 10, 27, 11); Instant instant = Instant.ofEpochMilli(epochTimeMillis); - ZoneId zoneId = ZoneId.systemDefault(); + ZoneId zoneId = ZoneId.of("UTC"); LocalDateTime actualDateTime = instant.atZone(zoneId).toLocalDateTime(); assertEquals(expectedDateTime, actualDateTime); From 7073d328c904d783344e58129e02fd22a5758c03 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 16:18:59 +0800 Subject: [PATCH 102/135] Update README.md [skip ci] --- spring-6-rsocket/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-6-rsocket/README.md b/spring-6-rsocket/README.md index 21ab282bd1..ef1f4994f2 100644 --- a/spring-6-rsocket/README.md +++ b/spring-6-rsocket/README.md @@ -3,5 +3,5 @@ This module contains articles about RSocket in Spring Framework 6. ### Relevant articles - -- [Introduction to RSocket](#) \ No newline at end of file +- [RSocket Interface in Spring 6](https://www.baeldung.com/spring-rsocket) +- [Introduction to RSocket](#) From 12809e524b59452290a2ecf0091d9cc210cb6679 Mon Sep 17 00:00:00 2001 From: panos-kakos <102670093+panos-kakos@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:54:51 +0300 Subject: [PATCH 103/135] [JAVA-25516] Upgraded spring-boot-actuator module to spring boot 3 (#14874) * [JAVA-25516] Upgraded spring-boot-actuator module to spring boot 3 * [JAVA-25516] Fixed issue related to actuator security --- .../spring-boot-actuator/pom.xml | 17 ++--- .../enabling/SecurityConfiguration.java | 66 ++++++++++++------- .../com/baeldung/endpoints/info/User.java | 8 +-- .../baeldung/metrics/MetricsApplication.java | 2 +- .../baeldung/metrics/filter/MetricFilter.java | 16 ++--- .../EndpointEnablingIntegrationTest.java | 6 +- 6 files changed, 63 insertions(+), 52 deletions(-) diff --git a/spring-boot-modules/spring-boot-actuator/pom.xml b/spring-boot-modules/spring-boot-actuator/pom.xml index 1ccf436bbf..7f630fa96e 100644 --- a/spring-boot-modules/spring-boot-actuator/pom.xml +++ b/spring-boot-modules/spring-boot-actuator/pom.xml @@ -9,9 +9,10 @@ This is simple boot application for Spring boot actuator test - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -39,16 +40,6 @@ com.h2database h2 - - javax.servlet - javax.servlet-api - provided - - - javax.servlet - jstl - runtime - org.springframework.boot spring-boot-starter-test diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java index 894c24693e..20ee834d52 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java @@ -1,36 +1,56 @@ package com.baeldung.endpoints.enabling; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; + import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; -import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -@Configuration @EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { +@Configuration +public class SecurityConfiguration { - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); - auth.inMemoryAuthentication() - .withUser("user") - .password(encoder.encode("password")) - .roles("USER") - .and() - .withUser("admin") - .password(encoder.encode("admin")) - .roles("USER", "ADMIN"); + @Bean + MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) { + return new MvcRequestMatcher.Builder(introspector); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()) - .authorizeRequests((requests) -> requests.anyRequest() - .hasRole("ADMIN")); - http.httpBasic(); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception { + http.httpBasic(Customizer.withDefaults()); + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests(authz -> { + authz.requestMatchers(mvc.pattern("/actuator/**")) + .hasRole("ADMIN") + .anyRequest() + .authenticated(); + }); + + return http.build(); + } + + + + @Bean + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + UserDetails admin = User.withDefaultPasswordEncoder() + .username("admin") + .password("password") + .roles("USER", "ADMIN") + .build(); + return new InMemoryUserDetailsManager(user, admin); } } diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java index db4e69127a..88f39d8ccc 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java @@ -1,9 +1,9 @@ package com.baeldung.endpoints.info; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "users") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java index 729b3c0b96..ee87412986 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java @@ -15,7 +15,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.context.request.RequestContextListener; -import javax.servlet.ServletContext; +import jakarta.servlet.ServletContext; @EnableScheduling @ComponentScan("com.baeldung.metrics") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java index 0f7579f060..a7aaddf0fb 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java @@ -7,14 +7,14 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @Component public class MetricFilter implements Filter { diff --git a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java index 8274619517..079195714b 100644 --- a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java +++ b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java @@ -13,20 +13,20 @@ import org.springframework.test.web.servlet.MockMvc; @SpringBootTest @AutoConfigureMockMvc -public class EndpointEnablingIntegrationTest { +class EndpointEnablingIntegrationTest { @Autowired private MockMvc mockMvc; @Test @WithMockUser(username = "user", password = "password", roles = "USER") - public void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception { + void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception { mockMvc.perform(get("/actuator")) .andExpect(status().isForbidden()); } @Test @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") - public void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception { + void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception { mockMvc.perform(get("/actuator")) .andExpect(jsonPath("$._links").exists()) .andExpect(jsonPath("$._links.beans").exists()) From 888734d76028e98957192498483fd3770fdf96c0 Mon Sep 17 00:00:00 2001 From: panos-kakos <102670093+panos-kakos@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:12:33 +0300 Subject: [PATCH 104/135] [JAVA-25518] Upgraded spring-boot-mvc-4 module to spring boot 3 (#14860) --- spring-boot-modules/spring-boot-mvc-4/pom.xml | 7 ++++--- .../controller/servlet/HelloWorldServlet.java | 8 ++++---- .../servlet/SpringHelloWorldServlet.java | 8 ++++---- .../SpringHelloServletRegistrationBean.java | 2 +- .../configuration/WebAppInitializer.java | 6 +++--- .../servlets/servlets/GenericCustomServlet.java | 8 ++++---- .../servlets/javaee/AnnotationServlet.java | 10 +++++----- .../servlets/javaee/EEWebXmlServlet.java | 8 ++++---- .../com/baeldung/utils/UtilsApplication.java | 2 +- .../utils/controller/UtilsController.java | 2 +- .../utils/UtilsControllerIntegrationTest.java | 16 +++++++++------- 11 files changed, 40 insertions(+), 37 deletions(-) diff --git a/spring-boot-modules/spring-boot-mvc-4/pom.xml b/spring-boot-modules/spring-boot-mvc-4/pom.xml index dbbb03ad0e..0ae05a764b 100644 --- a/spring-boot-modules/spring-boot-mvc-4/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-4/pom.xml @@ -9,9 +9,10 @@ Module For Spring Boot MVC Web - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java index 80c75aa8b5..cedc60bd92 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java @@ -4,10 +4,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Objects; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; public class HelloWorldServlet extends HttpServlet { private static final long serialVersionUID = 1L; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java index f276f94b7c..dbb8ea1b32 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java @@ -4,10 +4,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Objects; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; public class SpringHelloWorldServlet extends HttpServlet { private static final long serialVersionUID = 1L; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java index 3f51a4ab69..b2d6f249a5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java @@ -2,7 +2,7 @@ package com.baeldung.common.error; import org.springframework.boot.web.servlet.ServletRegistrationBean; -import javax.servlet.Servlet; +import jakarta.servlet.Servlet; public class SpringHelloServletRegistrationBean extends ServletRegistrationBean { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java index eadd40355a..7fd83fd59a 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java @@ -4,9 +4,9 @@ import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRegistration; public class WebAppInitializer implements WebApplicationInitializer { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java index 49dd9404b7..ee70a142be 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java @@ -1,9 +1,9 @@ package com.baeldung.servlets.servlets; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java index 992976ca0e..62706be348 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java @@ -1,10 +1,10 @@ package com.baeldung.servlets.servlets.javaee; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" }) diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java index c7b373064f..299a1b5d95 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java @@ -1,9 +1,9 @@ package com.baeldung.servlets.servlets.javaee; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java index ce3eae7ce0..eab5869cd5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java @@ -1,6 +1,6 @@ package com.baeldung.utils; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java index 8c7f2f932a..40acc1801f 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java @@ -1,6 +1,6 @@ package com.baeldung.utils.controller; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java index 080f660c40..f59d00f871 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java @@ -1,32 +1,34 @@ package com.baeldung.utils; import com.baeldung.utils.controller.UtilsController; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; + import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import static org.mockito.MockitoAnnotations.openMocks; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -public class UtilsControllerIntegrationTest { +class UtilsControllerIntegrationTest { @InjectMocks private UtilsController utilsController; private MockMvc mockMvc; - @Before + @BeforeEach public void setup() { - MockitoAnnotations.initMocks(this); + openMocks(this); this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build(); } @Test - public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception { + void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception { String param = "testparam"; this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk()); } From bcc3050383893834f448f0d369281d86a78bc6e9 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:20:51 +0800 Subject: [PATCH 105/135] Update README.md [skip ci] --- testing-modules/junit-5-advanced/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/testing-modules/junit-5-advanced/README.md b/testing-modules/junit-5-advanced/README.md index a89bcd2de2..873ab0835b 100644 --- a/testing-modules/junit-5-advanced/README.md +++ b/testing-modules/junit-5-advanced/README.md @@ -9,3 +9,4 @@ - [JUnit – Testing Methods That Call System.exit()](https://www.baeldung.com/junit-system-exit) - [Single Assert Call for Multiple Properties in Java Unit Testing](https://www.baeldung.com/java-testing-single-assert-multiple-properties) - [Creating a Test Suite With JUnit](https://www.baeldung.com/java-junit-test-suite) +- [Testing Interface Contract in Java](https://www.baeldung.com/java-junit-verify-interface-contract) From 06f1bfb9df0b893d5baf5be8b8bab1cac098192c Mon Sep 17 00:00:00 2001 From: anuragkumawat Date: Thu, 5 Oct 2023 16:51:31 +0530 Subject: [PATCH 106/135] JAVA-25096 Upgrade parent-spring-6 to the latest version of Spring (#14854) --- parent-spring-6/pom.xml | 2 +- spring-6-rsocket/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parent-spring-6/pom.xml b/parent-spring-6/pom.xml index 7b61ac524b..7b28afc9b1 100644 --- a/parent-spring-6/pom.xml +++ b/parent-spring-6/pom.xml @@ -35,7 +35,7 @@ - 6.0.10 + 6.0.12 diff --git a/spring-6-rsocket/README.md b/spring-6-rsocket/README.md index 21ab282bd1..2a8a197670 100644 --- a/spring-6-rsocket/README.md +++ b/spring-6-rsocket/README.md @@ -4,4 +4,4 @@ This module contains articles about RSocket in Spring Framework 6. ### Relevant articles -- [Introduction to RSocket](#) \ No newline at end of file +- [Introduction to RSocket](https://www.baeldung.com/spring-rsocket) From 11cea0a95623fae168a78a2f45efc24991e0f564 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:26:10 +0800 Subject: [PATCH 107/135] Update README.md [skip ci] --- core-java-modules/core-java-21/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md index 2c51db275a..b2e6aa6442 100644 --- a/core-java-modules/core-java-21/README.md +++ b/core-java-modules/core-java-21/README.md @@ -1,3 +1,4 @@ ## Relevant Articles - [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) - [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates) +- [Unnamed Classes and Instance Main Methods in Java 21](https://www.baeldung.com/java-21-unnamed-class-instance-main) From fb0ff7be4935c743000688ae5fd1ed4655986b52 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:29:36 +0800 Subject: [PATCH 108/135] Create README.md [skip ci] --- spring-boot-modules/spring-boot-graalvm-docker/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 spring-boot-modules/spring-boot-graalvm-docker/README.md diff --git a/spring-boot-modules/spring-boot-graalvm-docker/README.md b/spring-boot-modules/spring-boot-graalvm-docker/README.md new file mode 100644 index 0000000000..10a764053e --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image) From 4151a02bb68b1937db57152e57fc80e1ccc4a6f7 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:34:57 +0800 Subject: [PATCH 109/135] Update README.md [skip ci] --- core-java-modules/core-java-21/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md index b2e6aa6442..ffb999a4ba 100644 --- a/core-java-modules/core-java-21/README.md +++ b/core-java-modules/core-java-21/README.md @@ -2,3 +2,4 @@ - [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) - [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates) - [Unnamed Classes and Instance Main Methods in Java 21](https://www.baeldung.com/java-21-unnamed-class-instance-main) +- [Unnamed Patterns and Variables in Java 21](https://www.baeldung.com/java-unnamed-patterns-variables) From cb0bccfbd419a74e9735617ab94ec674f9909b70 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 21:39:55 +0800 Subject: [PATCH 110/135] Update README.md [skip ci] --- core-java-modules/core-java-regex-2/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/core-java-regex-2/README.md b/core-java-modules/core-java-regex-2/README.md index 02e470cce5..404b33b65f 100644 --- a/core-java-modules/core-java-regex-2/README.md +++ b/core-java-modules/core-java-regex-2/README.md @@ -9,4 +9,5 @@ - [Regular Expression: \z vs \Z Anchors in Java](https://www.baeldung.com/java-regular-expression-z-vs-z-anchors) - [Extract Text Between Square Brackets](https://www.baeldung.com/java-get-content-between-square-brackets) - [Get the Indexes of Regex Pattern Matches in Java](https://www.baeldung.com/java-indexes-regex-pattern-matches) +- [Check if a String is Strictly Alphanumeric With Java](https://www.baeldung.com/java-check-string-contains-only-letters-numbers) - More articles: [[<-- prev]](/core-java-modules/core-java-regex) From a9e906aa69fc00c7200b9d10df5363bfb68aa298 Mon Sep 17 00:00:00 2001 From: edizor <113095366+edizor@users.noreply.github.com> Date: Thu, 5 Oct 2023 21:43:16 +0800 Subject: [PATCH 111/135] Update README.md [skip ci] --- core-java-modules/core-java-collections-array-list-2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md index dbf5c47edb..575e0dbb07 100644 --- a/core-java-modules/core-java-collections-array-list-2/README.md +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -3,4 +3,4 @@ This module contains articles about the Java ArrayList collection ### Relevant Articles: -- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/arraylist-with-multiple-object-types) +- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/java-arraylist-multiple-object-types) From 68fd94288d141c87381ca9deeca3284dfd54cce9 Mon Sep 17 00:00:00 2001 From: mcasari Date: Fri, 6 Oct 2023 21:57:56 +0200 Subject: [PATCH 112/135] change string constructor test case in simpler form --- .../baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java index 9d125f557d..f783d00976 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -24,8 +24,8 @@ class FloatToBigDecimalUnitTest { @Test public void whenCreatedFromString_thenPreservesTheOriginal() { - BigDecimal bdFromString = new BigDecimal("1.10000002384185791015625"); - assertEquals("1.10000002384185791015625", bdFromString.toString()); + BigDecimal bdFromString = new BigDecimal("1.1"); + assertEquals("1.1", bdFromString.toString()); } @Test From 5dcd7e88d0e13e86789120053206f9586d37daf6 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 6 Oct 2023 20:00:28 -0400 Subject: [PATCH 113/135] implementing BAEL-6833 (#14912) Co-authored-by: technoddy --- libraries-io/pom.xml | 21 +++++ .../java/io/pojotocsv/Application.java | 4 + .../pojotocsv/ApplicationWithAnnotation.java | 8 ++ .../baeldung/java/io/pojotocsv/BeanToCsv.java | 55 +++++++++++++ .../CustomColumnPositionStrategy.java | 12 +++ .../io/pojotocsv/CustomHeaderStrategy.java | 16 ++++ .../src/main/resources/application.csv | 4 + .../src/main/resources/application2.csv | 4 + .../src/main/resources/application3.csv | 3 + .../src/main/resources/application4.csv | 4 + .../java/io/pojotocsv/BeanToCsvUnitTest.java | 80 +++++++++++++++++++ 11 files changed, 211 insertions(+) create mode 100644 libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java create mode 100644 libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java create mode 100644 libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java create mode 100644 libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java create mode 100644 libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java create mode 100644 libraries-io/src/main/resources/application.csv create mode 100644 libraries-io/src/main/resources/application2.csv create mode 100644 libraries-io/src/main/resources/application3.csv create mode 100644 libraries-io/src/main/resources/application4.csv create mode 100644 libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java diff --git a/libraries-io/pom.xml b/libraries-io/pom.xml index e92f6e11e1..fa89ebeabe 100644 --- a/libraries-io/pom.xml +++ b/libraries-io/pom.xml @@ -5,6 +5,18 @@ 4.0.0 libraries-io libraries-io + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + com.baeldung @@ -34,6 +46,11 @@ zip4j ${zip4j.version} + + com.opencsv + opencsv + ${opencsv.version} + @@ -42,6 +59,10 @@ 0.27.0 2.4 2.9.0 + 5.7.1 + 17 + 17 + UTF-8 \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java new file mode 100644 index 0000000000..b84da6229b --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java @@ -0,0 +1,4 @@ +package com.baeldung.java.io.pojotocsv; + +public record Application(String id, String name, Integer age, String created_at) { +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java new file mode 100644 index 0000000000..a0cd158843 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java @@ -0,0 +1,8 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.CsvBindByName; +import com.opencsv.bean.CsvBindByPosition; + +public record ApplicationWithAnnotation(@CsvBindByName(column = "id", required = true) @CsvBindByPosition(position = 1) String id, @CsvBindByName(column = "name", required = true) @CsvBindByPosition(position = 0) String name, + @CsvBindByName(column = "age", required = true) @CsvBindByPosition(position = 2) Integer age, @CsvBindByName(column = "position", required = true) @CsvBindByPosition(position = 3) String created_at) { +} \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java new file mode 100644 index 0000000000..f66c16beda --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java @@ -0,0 +1,55 @@ +package com.baeldung.java.io.pojotocsv; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +import com.opencsv.CSVWriter; +import com.opencsv.bean.StatefulBeanToCsvBuilder; +import com.opencsv.exceptions.CsvDataTypeMismatchException; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class BeanToCsv { + + public void beanToCSVWithDefault(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withSeparator(',') + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application2.csv")) { + var mappingStrategy = new CustomHeaderStrategy(); + mappingStrategy.setType(Application.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomPositionStrategy(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application3.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderAndPositionStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application4.csv")) { + var mappingStrategy = new CustomColumnPositionStrategy(); + mappingStrategy.setType(ApplicationWithAnnotation.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java new file mode 100644 index 0000000000..204bf3f917 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java @@ -0,0 +1,12 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.ColumnPositionMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomColumnPositionStrategy extends ColumnPositionMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + super.generateHeader(bean); + return super.getColumnMapping(); + } +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java new file mode 100644 index 0000000000..8e81c8ec28 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java @@ -0,0 +1,16 @@ +package com.baeldung.java.io.pojotocsv; + +import java.util.Arrays; + +import com.opencsv.bean.HeaderColumnNameMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomHeaderStrategy extends HeaderColumnNameMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + String[] header = super.generateHeader(bean); + return Arrays.stream(header) + .map(String::toLowerCase) + .toArray(String[]::new); + } +} diff --git a/libraries-io/src/main/resources/application.csv b/libraries-io/src/main/resources/application.csv new file mode 100644 index 0000000000..d4040e18e1 --- /dev/null +++ b/libraries-io/src/main/resources/application.csv @@ -0,0 +1,4 @@ +AGE,CREATED_AT,ID,NAME +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application2.csv b/libraries-io/src/main/resources/application2.csv new file mode 100644 index 0000000000..92bbced703 --- /dev/null +++ b/libraries-io/src/main/resources/application2.csv @@ -0,0 +1,4 @@ +age,created_at,id,name +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application3.csv b/libraries-io/src/main/resources/application3.csv new file mode 100644 index 0000000000..165107b103 --- /dev/null +++ b/libraries-io/src/main/resources/application3.csv @@ -0,0 +1,3 @@ +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/main/resources/application4.csv b/libraries-io/src/main/resources/application4.csv new file mode 100644 index 0000000000..b7999ae227 --- /dev/null +++ b/libraries-io/src/main/resources/application4.csv @@ -0,0 +1,4 @@ +name,id,age,created_at +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java new file mode 100644 index 0000000000..50cd1b1e0e --- /dev/null +++ b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.java.io.pojotocsv; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BeanToCsvUnitTest { + + List applications = new ArrayList<>(); + List applicationsWithAnnotation = new ArrayList<>(); + + @BeforeEach + public void beforeEach() { + applications = List.of(new Application("123", "Sam", 34, "2023-08-11"), new Application("456", "Tam", 44, "2023-02-11"), new Application("890", "Jam", 54, "2023-03-11")); + + applicationsWithAnnotation = List.of(new ApplicationWithAnnotation("123", "Sam", 34, "2023-08-11"), new ApplicationWithAnnotation("456", "Tam", 44, "2023-02-11"), new ApplicationWithAnnotation("789", "Jam", 54, "2023-03-11")); + } + + @Test + public void givenApplicationPOJO_whenUsingDefaultStrategy_thenReceiveCSVFormatWithAscendingOrderOfField() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithDefault(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("AGE,CREATED_AT,ID,NAME"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJO_whenUsingCustomHeaderStrategy_thenReceiveCSVFormatWithCustomHeaders() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderStrategy(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application2.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("age,created_at,id,name"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomPositionStrategy_thenReceiveCSVFormatWithCustomPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application3.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(1)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(2)).isEqualTo("Jam,789,54,2023-03-11"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomHeaderPositionStrategy_thenReceiveCSVFormatWithCustomHeaderPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderAndPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application4.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("name,id,age,created_at"); + assertThat(content.get(1)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(2)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(3)).isEqualTo("Jam,789,54,2023-03-11"); + } + } +} From 5aea5d5c296ed1471436de74fb57a603ab98dd44 Mon Sep 17 00:00:00 2001 From: etrandafir93 <75391049+etrandafir93@users.noreply.github.com> Date: Sat, 7 Oct 2023 06:11:47 +0200 Subject: [PATCH 114/135] BAEL-6782: partitioning streams (#14833) * BAEL-6782: partitioning streams * BAEL-6782: code reivew * BAEL-6782: line continuations --- core-java-modules/core-java-streams-5/pom.xml | 6 ++ .../streams/partitioning/PartitionStream.java | 90 +++++++++++++++++++ .../PartitionStreamsUnitTest.java | 82 +++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java create mode 100644 core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java diff --git a/core-java-modules/core-java-streams-5/pom.xml b/core-java-modules/core-java-streams-5/pom.xml index dc97d81b3d..d7baf84d30 100644 --- a/core-java-modules/core-java-streams-5/pom.xml +++ b/core-java-modules/core-java-streams-5/pom.xml @@ -43,6 +43,11 @@ vavr ${vavr.version} + + com.google.guava + guava + ${guava.version} + @@ -72,6 +77,7 @@ 12 12 0.10.2 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java new file mode 100644 index 0000000000..1ef3fa7707 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java @@ -0,0 +1,90 @@ +package com.baeldung.streams.partitioning; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import com.google.common.collect.Iterables; + +public class PartitionStream { + + public static Stream> partitionList(List source, int batchSize) { + if (batchSize <= 0) { + throw new IllegalArgumentException(String.format("Expected the batchSize to be greater than ZERO, actual value was: %s", batchSize)); + } + if (source.isEmpty()) { + return Stream.empty(); + } + int nrOfFullBatches = (source.size() - 1) / batchSize; + return IntStream.rangeClosed(0, nrOfFullBatches) + .mapToObj(batch -> { + int startIndex = batch * batchSize; + int endIndex = (batch == nrOfFullBatches) ? source.size() : (batch + 1) * batchSize; + return source.subList(startIndex, endIndex); + }); + } + + public static Iterable> partitionUsingGuava(Stream source, int batchSize) { + return Iterables.partition(source::iterator, batchSize); + } + + public static List> partitionStream(Stream source, int batchSize) { + return source.collect(partitionBySize(batchSize, Collectors.toList())); + } + + public static Collector partitionBySize(int batchSize, Collector, A, R> downstream) { + Supplier> supplier = () -> new Accumulator<>( + batchSize, + downstream.supplier().get(), + downstream.accumulator()::accept + ); + + BiConsumer, T> accumulator = (acc, value) -> acc.add(value); + + BinaryOperator> combiner = (acc1, acc2) -> acc1.combine(acc2, downstream.combiner()); + + Function, R> finisher = acc -> { + if (!acc.values.isEmpty()) { + downstream.accumulator().accept(acc.downstreamAccumulator, acc.values); + } + return downstream.finisher().apply(acc.downstreamAccumulator); + }; + + return Collector.of(supplier, accumulator, combiner, finisher, Collector.Characteristics.UNORDERED); + } + + static class Accumulator { + private final List values = new ArrayList<>(); + private final int batchSize; + private A downstreamAccumulator; + private final BiConsumer> batchFullListener; + + Accumulator(int batchSize, A accumulator, BiConsumer> onBatchFull) { + this.batchSize = batchSize; + this.downstreamAccumulator = accumulator; + this.batchFullListener = onBatchFull; + } + + void add(T value) { + values.add(value); + if (values.size() == batchSize) { + batchFullListener.accept(downstreamAccumulator, new ArrayList<>(values)); + values.clear(); + } + } + + Accumulator combine(Accumulator other, BinaryOperator accumulatorCombiner) { + this.downstreamAccumulator = accumulatorCombiner.apply(downstreamAccumulator, other.downstreamAccumulator); + other.values.forEach(this::add); + return this; + } + } + +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java new file mode 100644 index 0000000000..df75e69783 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java @@ -0,0 +1,82 @@ +package com.baeldung.partitioning; + +import static com.baeldung.streams.partitioning.PartitionStream.partitionList; +import static com.baeldung.streams.partitioning.PartitionStream.partitionStream; +import static com.baeldung.streams.partitioning.PartitionStream.partitionUsingGuava; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.atIndex; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class PartitionStreamsUnitTest { + + @Test + void whenPartitionList_thenReturnThreeSubLists() { + List source = List.of(1, 2, 3, 4, 5, 6, 7, 8); + + Stream> result = partitionList(source, 3); + + assertThat(result) + .containsExactlyInAnyOrder( + List.of(1, 2, 3), + List.of(4, 5, 6), + List.of(7, 8) + ); + } + + @Test + void whenPartitionEmptyList_thenReturnEmptyStream() { + Stream> result = partitionList(Collections.emptyList(), 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionListWithNegativeBatchSize_thenThrowException() { + assertThatThrownBy(() -> partitionList(List.of(1,2,3), -1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Expected the batchSize to be greater than ZERO, actual value was: -1"); + } + + @Test + void whenPartitionParallelStream_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result) + .hasSize(3) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).hasSize(2), atIndex(2)); + } + + @Test + void whenPartitionEmptyParallelStream_thenReturnEmptyList() { + Stream source = Stream.empty().parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionParallelStreamWithGuava_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + Iterable> result = partitionUsingGuava(source, 3); + + assertThat(result) + .map(ArrayList::new) + .hasSize(3) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).asList().hasSize(2), atIndex(2)); + } +} From ed2f3234e6574f814adb24323ae3bedc6b1b29d7 Mon Sep 17 00:00:00 2001 From: Constantin <50400363+constantinurs@users.noreply.github.com> Date: Sat, 7 Oct 2023 07:21:30 +0300 Subject: [PATCH 115/135] BAEL-6612: How to subscribe a Kafka consumer to multiple topics (#14800) * BAEL-6612: Subscribe consumer to multiple topics using Spring Kafka * BAEL-6612: Subscribe consumer to multiple topics using Apache Kafka * BAEL-6612: Revert README files * BAEL-6612: Fix identation; remove static qualifier * BAEL-6612: Fix identation; remove static qualifier --- .../MultipleTopicsLiveTest.java | 103 ++++++++++++++++++ .../multipletopics/KafkaConsumerConfig.java | 36 ++++++ .../KafkaMultipleTopicsApplication.java | 13 +++ .../multipletopics/KafkaProducerConfig.java | 34 ++++++ .../kafka/multipletopics/PaymentData.java | 54 +++++++++ .../multipletopics/PaymentDataListener.java | 18 +++ .../KafkaMultipleTopicsIntegrationTest.java | 78 +++++++++++++ 7 files changed, 336 insertions(+) create mode 100644 apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java create mode 100644 spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java create mode 100644 spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java create mode 100644 spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java create mode 100644 spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java create mode 100644 spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java create mode 100644 spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java diff --git a/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java new file mode 100644 index 0000000000..653456a678 --- /dev/null +++ b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java @@ -0,0 +1,103 @@ +package com.baeldung.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.ExecutionException; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +// This live test needs a Docker Daemon running so that a kafka container can be created + +@Testcontainers +public class MultipleTopicsLiveTest { + + private final Logger log = LoggerFactory.getLogger(MultipleTopicsLiveTest.class); + + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + private static KafkaProducer producer; + private static KafkaConsumer consumer; + + @Container + private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest")); + + @BeforeAll + static void setup() { + KAFKA_CONTAINER.addExposedPort(9092); + producer = new KafkaProducer<>(getProducerProperties()); + consumer = new KafkaConsumer<>(getConsumerProperties()); + } + + @AfterAll + static void destroy() { + KAFKA_CONTAINER.stop(); + } + + private static Properties getProducerProperties() { + Properties producerProperties = new Properties(); + producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + return producerProperties; + } + + private static Properties getConsumerProperties() { + Properties consumerProperties = new Properties(); + consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "payments"); + return consumerProperties; + } + + @Test + void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + publishMessages(); + + consumer.subscribe(Arrays.asList(CARD_PAYMENTS_TOPIC, BANK_TRANSFERS_TOPIC)); + + int eventsProcessed = 0; + for (ConsumerRecord record : consumer.poll(Duration.ofSeconds(10))) { + log.info("Event on topic={}, payload={}", record.topic(), record.value()); + eventsProcessed++; + } + + assertThat(eventsProcessed).isEqualTo(2); + } + + private void publishMessages() throws ExecutionException, InterruptedException { + ProducerRecord cardPayment = new ProducerRecord<>(CARD_PAYMENTS_TOPIC, createCardPayment()); + producer.send(cardPayment).get(); + + ProducerRecord bankTransfer = new ProducerRecord<>(BANK_TRANSFERS_TOPIC, createBankTransfer()); + producer.send(bankTransfer).get(); + } + + private String createCardPayment() { + return "{\"paymentReference\":\"A184028KM0013790\", \"type\":\"card\", \"amount\":\"275\", \"currency\":\"GBP\"}"; + } + + private String createBankTransfer() { + return "{\"paymentReference\":\"19ae2-18mk73-009\", \"type\":\"bank\", \"amount\":\"150\", \"currency\":\"EUR\"}"; + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java new file mode 100644 index 0000000000..741fb6bba4 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; + +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ConsumerFactory consumerFactory() { + Map config = new HashMap<>(); + config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(), new JsonDeserializer<>(PaymentData.class)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java new file mode 100644 index 0000000000..2135a27f39 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.kafka.annotation.EnableKafka; + +@EnableKafka +@SpringBootApplication +public class KafkaMultipleTopicsApplication { + public static void main(String[] args) { + SpringApplication.run(KafkaMultipleTopicsApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java new file mode 100644 index 0000000000..2cb0117bf1 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ProducerFactory producerFactory() { + Map config = new HashMap<>(); + config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaProducerFactory<>(config, new StringSerializer(), new JsonSerializer<>()); + } + + @Bean + public KafkaTemplate kafkaProducer() { + return new KafkaTemplate<>(producerFactory()); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java new file mode 100644 index 0000000000..e81138c089 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.StringJoiner; + +public class PaymentData { + private String paymentReference; + private String type; + private BigDecimal amount; + private Currency currency; + + public String getPaymentReference() { + return paymentReference; + } + + public void setPaymentReference(String paymentReference) { + this.paymentReference = paymentReference; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + @Override + public String toString() { + return new StringJoiner(", ", PaymentData.class.getSimpleName() + "[", "]") + .add("paymentReference='" + paymentReference + "'") + .add("type='" + type + "'") + .add("amount=" + amount) + .add("currency=" + currency) + .toString(); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java new file mode 100644 index 0000000000..fb640cca25 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Service; + +@Service +public class PaymentDataListener { + private final Logger log = LoggerFactory.getLogger(PaymentDataListener.class); + + @KafkaListener(topics = { "card-payments", "bank-transfers" }, groupId = "payments") + public void handlePaymentEvents(PaymentData paymentData, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + log.info("Event on topic={}, payload={}", topic, paymentData); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java new file mode 100644 index 0000000000..345e84b65b --- /dev/null +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java @@ -0,0 +1,78 @@ +package com.baeldung.spring.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.kafka.test.utils.ContainerTestUtils; + +@SpringBootTest(classes = KafkaMultipleTopicsApplication.class) +@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +public class KafkaMultipleTopicsIntegrationTest { + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + + @Autowired + private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + + @Autowired + private KafkaTemplate kafkaProducer; + + @SpyBean + private PaymentDataListener paymentsConsumer; + + @BeforeEach + void setUp() { + // wait for embedded Kafka + for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry.getListenerContainers()) { + ContainerTestUtils.waitForAssignment(messageListenerContainer, 2); + } + } + + @Test + public void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + CountDownLatch countDownLatch = new CountDownLatch(2); + doAnswer(invocation -> { + countDownLatch.countDown(); + return null; + }).when(paymentsConsumer) + .handlePaymentEvents(any(), any()); + + kafkaProducer.send(CARD_PAYMENTS_TOPIC, createCardPayment()); + kafkaProducer.send(BANK_TRANSFERS_TOPIC, createBankTransfer()); + + assertThat(countDownLatch.await(5, TimeUnit.SECONDS)).isTrue(); + } + + private PaymentData createCardPayment() { + PaymentData cardPayment = new PaymentData(); + cardPayment.setAmount(BigDecimal.valueOf(275)); + cardPayment.setPaymentReference("A184028KM0013790"); + cardPayment.setCurrency(Currency.getInstance("GBP")); + cardPayment.setType("card"); + return cardPayment; + } + + private PaymentData createBankTransfer() { + PaymentData bankTransfer = new PaymentData(); + bankTransfer.setAmount(BigDecimal.valueOf(150)); + bankTransfer.setPaymentReference("19ae2-18mk73-009"); + bankTransfer.setCurrency(Currency.getInstance("EUR")); + bankTransfer.setType("bank"); + return bankTransfer; + } +} \ No newline at end of file From e62aba145b71066dbf8d6cf7a0490e7df73292ef Mon Sep 17 00:00:00 2001 From: Mo Helmy <135069400+BenHelmyBen@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:53:38 +0300 Subject: [PATCH 116/135] This commit related to the article BAEL-6877 (#14899) This commit aims to add a new Java module "core-java-collections-maps-7" --- .../core-java-collections-maps-7/README.md | 1 + .../core-java-collections-maps-7/pom.xml | 78 +++++++++++++++++++ ...MapStringToHashMapObjectUsingtoString.java | 60 ++++++++++++++ ...gToHashMapObjectUsingtoStringUnitTest.java | 31 ++++++++ 4 files changed, 170 insertions(+) create mode 100644 core-java-modules/core-java-collections-maps-7/README.md create mode 100644 core-java-modules/core-java-collections-maps-7/pom.xml create mode 100644 core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java create mode 100644 core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java diff --git a/core-java-modules/core-java-collections-maps-7/README.md b/core-java-modules/core-java-collections-maps-7/README.md new file mode 100644 index 0000000000..c63f3b360b --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/README.md @@ -0,0 +1 @@ +## Relevant Articles \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/pom.xml b/core-java-modules/core-java-collections-maps-7/pom.xml new file mode 100644 index 0000000000..bb7c6e9fb5 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + core-java-collections-maps-7 + core-java-collections-maps-7 + jar + + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + + + 5.2.5.RELEASE + + + + com.fasterxml.jackson.core + jackson-databind + 2.12.4 + + + org.openjdk.jmh + jmh-core + 1.36 + + + com.google.code.gson + gson + 2.8.9 + + + org.json + json + 20230227 + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java new file mode 100644 index 0000000000..2b3d6db89c --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java @@ -0,0 +1,60 @@ +package com.baeldung.map; + +import java.util.HashMap; +import java.util.Map; + +public class ConvertHashMapStringToHashMapObjectUsingtoString { + public String name; + public int age; + + public ConvertHashMapStringToHashMapObjectUsingtoString(String name, int age) { + this.name = name; + this.age = age; + } + + public static ConvertHashMapStringToHashMapObjectUsingtoString deserializeCustomObject(String valueString) { + if (valueString.startsWith("{") && valueString.endsWith("}")) { + valueString = valueString.substring(1, valueString.length() - 1); + String[] parts = valueString.split(","); + String name = null; + int age = -1; + for (String part : parts) { + String[] keyValue = part.split("="); + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String val = keyValue[1].trim(); + if (key.equals("name")) { + name = val; + } else if (key.equals("age")) { + age = Integer.parseInt(val); + } + } + } + if (name != null && age >= 0) { + return new ConvertHashMapStringToHashMapObjectUsingtoString(name, age); + } + } + return new ConvertHashMapStringToHashMapObjectUsingtoString("", -1); + } + + public static void main(String[] args) { + String hashMapString = "{key1={name=John, age=30}, key2={name=Alice, age=25}}"; + String keyValuePairs = hashMapString.replaceAll("[{}\\s]", ""); + String[] pairs = keyValuePairs.split(","); + Map actualHashMap = new HashMap<>(); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + String key = keyValue[0]; + ConvertHashMapStringToHashMapObjectUsingtoString value = deserializeCustomObject(keyValue[1]); + actualHashMap.put(key, value); + } + } + System.out.println(actualHashMap); + } + + @Override + public String toString() { + return "{name=" + name + ", age=" + age + "}"; + } +} diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java new file mode 100644 index 0000000000..7d31402131 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.map; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest { + + @Test + void givenValidCustomObject_whenSerializing_thenSerializedStringIsCorrect() { + ConvertHashMapStringToHashMapObjectUsingtoString customObject = new ConvertHashMapStringToHashMapObjectUsingtoString("John", 30); + String expectedSerializedString = "{name=John, age=30}"; + assertEquals(expectedSerializedString, customObject.toString()); + } + + @Test + void givenValidSerializedString_whenDeserializing_thenCustomObjectIsCorrect() { + String serializedString = "{name=Alice, age=25}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(serializedString); + assertEquals("Alice", customObject.name); + assertEquals(25, customObject.age); + } + + @Test + void givenInvalidSerializedString_whenDeserializing_thenDefaultCustomObjectIsCreated() { + String invalidSerializedString = "{invalidString}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(invalidSerializedString); + assertEquals("", customObject.name); + assertEquals(-1, customObject.age); + } +} From 3a816d6b3d134c06a5d8f9cbe8250b7511a02cfb Mon Sep 17 00:00:00 2001 From: vunamtien Date: Sat, 7 Oct 2023 20:04:59 +0700 Subject: [PATCH 117/135] BAEL-6967-decode-unicode-in-string (#14901) * BAEL-6967-decode-unicode-in-string * update unit test --------- Co-authored-by: tienvn --- libraries-apache-commons-2/pom.xml | 6 +++ .../convertunicode/UnicodeConverterUtil.java | 29 ++++++++++++++ .../UnicodeConverterUnitTest.java | 39 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml index d771aac9ab..ee9b51e6cc 100644 --- a/libraries-apache-commons-2/pom.xml +++ b/libraries-apache-commons-2/pom.xml @@ -28,12 +28,18 @@ commons-vfs2 ${commons-vfs2.version} + + org.apache.commons + commons-text + ${apache-commons-text.version} + 1.23.0 1.10.13 2.9.0 + 1.10.0 \ No newline at end of file diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java new file mode 100644 index 0000000000..c788f6ee61 --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java @@ -0,0 +1,29 @@ +package com.baeldung.commons.convertunicode; + +import org.apache.commons.text.StringEscapeUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UnicodeConverterUtil { + + public static String decodeWithApacheCommons(String input) { + return StringEscapeUtils.unescapeJava(input); + } + + public static String decodeWithPlainJava(String input) { + Pattern pattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); + Matcher matcher = pattern.matcher(input); + + StringBuilder decodedString = new StringBuilder(); + + while (matcher.find()) { + String unicodeSequence = matcher.group(); + char unicodeChar = (char) Integer.parseInt(unicodeSequence.substring(2), 16); + matcher.appendReplacement(decodedString, Character.toString(unicodeChar)); + } + + matcher.appendTail(decodedString); + return decodedString.toString(); + } +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java new file mode 100644 index 0000000000..f4a9bbcb77 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.commons.convertunicode; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UnicodeConverterUnitTest { + + @Test + public void whenInputHaveUnicodeSequences_ThenDecode() { + String encodedString = "\\u0048\\u0065\\u006C\\u006C\\u006F World"; + String expectedDecodedString = "Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveNoUnicodeSequences_ThenDoNothing() { + String inputString = "Hello World"; + assertEquals(inputString, UnicodeConverterUtil.decodeWithApacheCommons(inputString)); + assertEquals(inputString, UnicodeConverterUtil.decodeWithPlainJava(inputString)); + } + + @Test + public void whenInputHaveUnicodeSequencesInMiddle_ThenDecode() { + String encodedString = "This is a test \\u0069\\u006E the middle."; + String expectedDecodedString = "This is a test in the middle."; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveMultipleUnicodeSequences_ThenDecode() { + String encodedString = "Unicode: \\u0048\\u0065\\u006C\\u006C\\u006F \\u0057\\u006F\\u0072\\u006C\\u0064"; + String expectedDecodedString = "Unicode: Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } +} From 131d6757719ac3e603f94160ffcfde5346d5f292 Mon Sep 17 00:00:00 2001 From: balasr3 Date: Sat, 7 Oct 2023 14:48:34 +0100 Subject: [PATCH 118/135] BAEL-7032: updated with review comment on test --- .../baeldung/expression/mapper/LicenseMapperUnitTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java index 8c015674bc..d7521e81f5 100644 --- a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -76,7 +76,7 @@ class LicenseMapperUnitTest { } @Test - void givenLicenseDtoWithoutLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithoutLicenseType() { + void givenLicenseDtoWithoutLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { LicenseDto licenseDto = new LicenseDto(); License license = licenseMapper.toLicense(licenseDto); assertThat(license).isNotNull(); @@ -84,7 +84,7 @@ class LicenseMapperUnitTest { } @Test - void givenLicenseDtoWithInvalidLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithoutLicenseType() { + void givenLicenseDtoWithInvalidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { LicenseDto licenseDto = new LicenseDto(); licenseDto.setLicenseType("invalid_license_type"); License license = licenseMapper.toLicense(licenseDto); @@ -93,7 +93,7 @@ class LicenseMapperUnitTest { } @Test - void givenLicenseDtoWithValidLicenseTypeString_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithMatchingLicenseType() { + void givenLicenseDtoWithValidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithMatchingLicenseType() { LicenseDto licenseDto = new LicenseDto(); licenseDto.setLicenseType("INDIVIDUAL"); License license = licenseMapper.toLicense(licenseDto); From b7f3161bc517278aec132fedbd799c63bd896973 Mon Sep 17 00:00:00 2001 From: Kai Yuan Date: Mon, 9 Oct 2023 04:30:55 +0200 Subject: [PATCH 119/135] [bin-int-to-str] zero-padded binary string representation (#14885) --- .../IntegerToBinaryUnitTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java index 38ae79f2f5..9439f012e3 100644 --- a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java +++ b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.integerToBinary; +import org.apache.commons.lang3.StringUtils; import org.junit.Test; + import static org.junit.Assert.assertEquals; public class IntegerToBinaryUnitTest { @@ -24,4 +26,18 @@ public class IntegerToBinaryUnitTest { String binaryString = Integer.toString(n, 2); assertEquals("111", binaryString); } -} + + @Test + public void givenAnInteger_whenFormatAndReplaceCalled_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = String.format("%8s", Integer.toBinaryString(n)).replace(" ", "0"); + assertEquals("00000111", binaryString); + } + + @Test + public void givenAnInteger_whenUsingApacheStringUtils_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = StringUtils.leftPad(Integer.toBinaryString(n), 8, "0"); + assertEquals("00000111", binaryString); + } +} \ No newline at end of file From 0e7c032aa8c67fcd06a8e4a5d217ad2f8c4e3e22 Mon Sep 17 00:00:00 2001 From: Rufina Uche <102101377+Finniki@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:53:46 +0100 Subject: [PATCH 120/135] Javadoublevsbigdecimal (#14862) * Create BigDecimalConversionUnitTest.java * Add files via upload * Update BigDecimalConversionUnitTest.java * Update BigDecimalConversionUnitTest.java * Update BigDecimalConversionUnitTest.java --- .../BigDecimalConversionUnitTest.java | 28 +++++++++++++ .../BigDecimalUnitTest.java | 42 +++++++++++++++++++ .../JavaDoubleUnitTest.java | 15 +++++++ 3 files changed, 85 insertions(+) create mode 100644 core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java create mode 100644 core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java create mode 100644 core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java new file mode 100644 index 0000000000..76c218d85f --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalConversionUnitTest { + + @Test + void whenConvertingDoubleToBigDecimal_thenConversionIsCorrect() { + double doubleValue = 123.456; + BigDecimal bigDecimalValue = BigDecimal.valueOf(doubleValue); + BigDecimal expected = new BigDecimal("123.456").setScale(3, RoundingMode.HALF_UP); + assertEquals(expected, bigDecimalValue.setScale(3, RoundingMode.HALF_UP)); + } + + @Test + void givenDecimalPlacesGreaterThan15_whenConvertingBigDecimalToDouble_thenPrecisionIsLost() { + BigDecimal bigDecimalValue = new BigDecimal("789.1234567890123456"); + double doubleValue = bigDecimalValue.doubleValue(); + BigDecimal convertedBackToBigDecimal = BigDecimal.valueOf(doubleValue); + assertNotEquals(bigDecimalValue, convertedBackToBigDecimal); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java new file mode 100644 index 0000000000..3ee611f315 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalUnitTest { + + private BigDecimal bigDecimal1 = new BigDecimal("124567890.0987654321"); + private BigDecimal bigDecimal2 = new BigDecimal("987654321.123456789"); + + @Test + public void givenTwoBigDecimals_whenAdd_thenCorrect() { + BigDecimal expected = new BigDecimal("1112222211.2222222211"); + BigDecimal actual = bigDecimal1.add(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenMultiply_thenCorrect() { + BigDecimal expected = new BigDecimal("123030014929277547.5030955772112635269"); + BigDecimal actual = bigDecimal1.multiply(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenSubtract_thenCorrect() { + BigDecimal expected = new BigDecimal("-863086431.0246913569"); + BigDecimal actual = bigDecimal1.subtract(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenDivide_thenCorrect() { + BigDecimal expected = new BigDecimal("0.13"); + BigDecimal actual = bigDecimal1.divide(bigDecimal2, 2, RoundingMode.HALF_UP); + assertEquals(expected, actual); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java new file mode 100644 index 0000000000..8697e1bfce --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class JavaDoubleUnitTest { + + @Test + public void givenDoubleLiteral_whenAssigningToDoubleVariable_thenValueIsNotExactlyEqual() { + double doubleValue = 0.1; + double epsilon = 0.0000000000000001; + assertEquals(0.1, doubleValue, epsilon); + } +} From 901951bff763b3cc4df554d077f6d5930425a5e4 Mon Sep 17 00:00:00 2001 From: Harry9656 Date: Mon, 9 Oct 2023 09:53:54 +0200 Subject: [PATCH 121/135] BAEL-6898: Add Debug property for ssl Handshakes (#14822) --- .../java/com/baeldung/ssl/SecureConnection.java | 14 +++++++------- .../com/baeldung/ssl/example/SimpleClient.java | 7 +++---- .../com/baeldung/ssl/example/SimpleServer.java | 8 ++++---- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java index 36dee603eb..6f2e3250fc 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java @@ -7,7 +7,7 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class SecureConnection { - + public static void main(String[] args) { if (args.length != 2) { System.out.println("Use: SecureConnection host port"); @@ -20,20 +20,20 @@ public class SecureConnection { SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port); InputStream in = sslsocket.getInputStream(); OutputStream out = sslsocket.getOutputStream(); - + out.write(1); - + while (in.available() > 0) { System.out.print(in.read()); } - + System.out.println("Secured connection performed successfully"); - + } catch (Exception exception) { exception.printStackTrace(); } } - + /** * Get the host from arguments * @param args the arguments @@ -42,7 +42,7 @@ public class SecureConnection { private static String getHost(String[] args) { return args[0]; } - + /** * Get the port from arguments * @param args the arguments diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java index d6efc34c3e..cf9a76b39a 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java @@ -15,10 +15,8 @@ public class SimpleClient { SocketFactory factory = SSLSocketFactory.getDefault(); try (Socket connection = factory.createSocket(host, port)) { - ((SSLSocket) connection).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLSocket) connection).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLSocket) connection).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLSocket) connection).setEnabledProtocols(new String[] { "TLSv1.2" }); SSLParameters sslParams = new SSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); ((SSLSocket) connection).setSSLParameters(sslParams); @@ -28,6 +26,7 @@ public class SimpleClient { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); System.out.println(startClient("localhost", 8443)); } } diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java index 27d15d04d7..83946ccc1f 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java @@ -14,11 +14,10 @@ public class SimpleServer { ServerSocketFactory factory = SSLServerSocketFactory.getDefault(); try (ServerSocket listener = factory.createServerSocket(port)) { + System.setProperty("javax.net.debug", "ssl:handshake"); ((SSLServerSocket) listener).setNeedClientAuth(true); - ((SSLServerSocket) listener).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLServerSocket) listener).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLServerSocket) listener).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLServerSocket) listener).setEnabledProtocols(new String[] { "TLSv1.2" }); while (true) { try (Socket socket = listener.accept()) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); @@ -29,6 +28,7 @@ public class SimpleServer { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); startServer(8443); } } \ No newline at end of file From 52f4344bceeece2e05d4a515bac46d7d8fcfb313 Mon Sep 17 00:00:00 2001 From: Azhwani <13301425+azhwani@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:55:29 +0200 Subject: [PATCH 122/135] BAEL-7057: How to convert CharSequence to String? (#14892) --- .../CharSequenceVsStringUnitTest.java | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java index aa15345bcb..13a0407a98 100644 --- a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java +++ b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java @@ -1,11 +1,11 @@ package com.baeldung.charsequence; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import org.junit.Test; + public class CharSequenceVsStringUnitTest { @Test @@ -44,4 +44,43 @@ public class CharSequenceVsStringUnitTest { assertEquals(firstAddressOfTest, secondAddressOfTest); } + + @Test + public void givenCharSequenceAsString_whenConvertingUsingCasting_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence = "baeldung"; + String explicitCastedString = (String) charSequence; + + assertEquals(expected, charSequence); + assertEquals(expected, explicitCastedString); + } + + @Test(expected = ClassCastException.class) + public void givenCharSequenceAsStringBuiler_whenConvertingUsingCasting_thenThrowException() { + CharSequence charSequence = new StringBuilder("baeldung"); + String castedString = (String) charSequence; + } + + @Test + public void givenCharSequence_whenConvertingUsingToString_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + + assertEquals(expected, charSequence1.toString()); + assertEquals(expected, charSequence2.toString()); + } + + @Test + public void givenCharSequence_whenConvertingUsingValueOf_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + CharSequence charSequence3 = null; + + assertEquals(expected, String.valueOf(charSequence1)); + assertEquals(expected, String.valueOf(charSequence2)); + assertEquals("null", String.valueOf(charSequence3)); + } + } From 1f3252df75b2381fd8d11016b5925c8d1910ed12 Mon Sep 17 00:00:00 2001 From: Azhwani <13301425+azhwani@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:57:03 +0200 Subject: [PATCH 123/135] BAEL-6714: Convert Char Array to Int Array in Java (#14875) --- .../conversions/CharArrayToIntArrayUtils.java | 67 +++++++++++++++++++ .../CharArrayToIntArrayUtilsUnitTest.java | 54 +++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java create mode 100644 core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java diff --git a/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java new file mode 100644 index 0000000000..fbd76a0113 --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java @@ -0,0 +1,67 @@ +package com.baeldung.array.conversions; + +import java.util.Arrays; + +public class CharArrayToIntArrayUtils { + + static int[] usingGetNumericValueMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.getNumericValue(chars[i]); + } + + return ints; + } + + static int[] usingDigitMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.digit(chars[i], 10); + } + + return ints; + } + + static int[] usingStreamApiMethod(char[] chars) { + if (chars == null) { + return null; + } + + return new String(chars).chars() + .map(c -> c - 48) + .toArray(); + } + + static int[] usingParseIntMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Integer.parseInt(String.valueOf(chars[i])); + } + + return ints; + } + + static int[] usingArraysSetAllMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + Arrays.setAll(ints, i -> Character.getNumericValue(chars[i])); + + return ints; + } + +} diff --git a/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java new file mode 100644 index 0000000000..534dc3893f --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.array.conversions; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +class CharArrayToIntArrayUtilsUnitTest { + + @Test + void givenCharArray_whenUsingGetNumericValueMethod_shouldGetIntArray() { + int[] expected = { 2, 3, 4, 5 }; + char[] chars = { '2', '3', '4', '5' }; + int[] result = CharArrayToIntArrayUtils.usingGetNumericValueMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingDigitMethod_shouldGetIntArray() { + int[] expected = { 1, 2, 3, 6 }; + char[] chars = { '1', '2', '3', '6' }; + int[] result = CharArrayToIntArrayUtils.usingDigitMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingStreamApi_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingStreamApiMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingParseIntMethod_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingParseIntMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingArraysSetAllMethod_shouldGetIntArray() { + int[] expected = { 4, 9, 2, 3 }; + char[] chars = { '4', '9', '2', '3' }; + int[] result = CharArrayToIntArrayUtils.usingArraysSetAllMethod(chars); + + assertArrayEquals(expected, result); + } + +} From bb29bb9dcd1582376ac8bdd67c3d67c192ff39c7 Mon Sep 17 00:00:00 2001 From: Mo Helmy <135069400+BenHelmyBen@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:17:30 +0300 Subject: [PATCH 124/135] Adding the new module to the main pom (#14924) * This commit related to the article BAEL-6877 This commit aims to add a new Java module "core-java-collections-maps-7" * Update pom.xml --- core-java-modules/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index cd31bb5845..ae9ff59222 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -83,6 +83,7 @@ core-java-collections-maps core-java-collections-maps-2 core-java-collections-maps-3 + core-java-collections-maps-7 core-java-compiler core-java-concurrency-2 core-java-concurrency-advanced From ff6d3e73935c9ad1243ff4e7c49a087d84ca9a28 Mon Sep 17 00:00:00 2001 From: mdabrowski-eu <57441874+mdabrowski-eu@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:33:39 +0200 Subject: [PATCH 125/135] BAEL-6911 fix dependencies issues, add missing snipets (#14935) --- spring-boot-modules/spring-boot-3/pom.xml | 8 ++- .../java/com/baeldung/restclient/Article.java | 10 +++ .../restclient/ArticleController.java | 19 ++++-- .../restclient/ArticleNotFoundException.java | 6 ++ .../InvalidArticleResponseException.java | 6 ++ .../restclient/RestClientIntegrationTest.java | 66 +++++++++++++++++-- 6 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java create mode 100644 spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index 7dd44c89dc..bb8c5dd53c 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -60,7 +60,11 @@ org.junit.jupiter junit-jupiter-params ${jupiter.version} - test + + + org.junit.platform + junit-platform-commons + 1.10.0 org.mock-server @@ -204,7 +208,7 @@ 19 1.5.2.Final - 2.0.0 + 2.2.0 3.0.0-M7 com.baeldung.sample.TodoApplication 5.14.0 diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java index a69d5989af..892cf3b5ae 100644 --- a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java @@ -6,6 +6,8 @@ public class Article { Integer id; String title; + public Article() {} + public Article(Integer id, String title) { this.id = id; this.title = title; @@ -19,6 +21,14 @@ public class Article { return title; } + public void setId(Integer id) { + this.id = id; + } + + public void setTitle(String title) { + this.title = title; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java index 62922bdcee..5e1dff6fd7 100644 --- a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java @@ -1,5 +1,6 @@ package com.baeldung.restclient; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Collection; @@ -13,13 +14,21 @@ public class ArticleController { Map database = new HashMap<>(); @GetMapping - public Collection
getArticles() { - return database.values(); + public ResponseEntity> getArticles() { + Collection
values = database.values(); + if (values.isEmpty()) { + return ResponseEntity.noContent().build(); + } + return ResponseEntity.ok(values); } @GetMapping("/{id}") - public Article getArticle(@PathVariable Integer id) { - return database.get(id); + public ResponseEntity
getArticle(@PathVariable("id") Integer id) { + Article article = database.get(id); + if (article == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(article); } @PostMapping @@ -28,7 +37,7 @@ public class ArticleController { } @PutMapping("/{id}") - public void updateArticle(@PathVariable Integer id, @RequestBody Article article) { + public void updateArticle(@PathVariable("id") Integer id, @RequestBody Article article) { assert Objects.equals(id, article.getId()); database.remove(id); database.put(id, article); diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java new file mode 100644 index 0000000000..cdd13b8330 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class ArticleNotFoundException extends RuntimeException { + public ArticleNotFoundException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java new file mode 100644 index 0000000000..26ca75036e --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class InvalidArticleResponseException extends RuntimeException { + public InvalidArticleResponseException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java index 92474c88f0..1a615faf4e 100644 --- a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java @@ -1,17 +1,23 @@ package com.baeldung.restclient; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClient; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -22,7 +28,10 @@ public class RestClientIntegrationTest { private String uriBase; RestClient restClient = RestClient.create(); - @BeforeAll + @Autowired + ObjectMapper objectMapper; + + @BeforeEach public void setup() { uriBase = "http://localhost:" + port; } @@ -42,7 +51,7 @@ public class RestClientIntegrationTest { .retrieve() .body(String.class); - assertThat(articlesAsString).isEqualTo("[]"); + assertThat(articlesAsString).isEqualTo(""); } @Test @@ -63,6 +72,48 @@ public class RestClientIntegrationTest { assertThat(articles).isEqualTo(List.of(article)); } + @Test + void shouldPostAndGetArticlesWithExchange() { + assertThatThrownBy(this::getArticlesWithExchange).isInstanceOf(ArticleNotFoundException.class); + + Article article = new Article(1, "How to use RestClient"); + restClient.post() + .uri(uriBase + "/articles") + .contentType(MediaType.APPLICATION_JSON) + .body(article) + .retrieve() + .toBodilessEntity(); + + List
articles = getArticlesWithExchange(); + + assertThat(articles).isEqualTo(List.of(article)); + } + + private List
getArticlesWithExchange() { + return restClient.get() + .uri(uriBase + "/articles") + .exchange((request, response) -> { + if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(204))) { + throw new ArticleNotFoundException(); + } else if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) { + return objectMapper.readValue(response.getBody(), new TypeReference<>() {}); + } else { + throw new InvalidArticleResponseException(); + } + }); + } + + @Test + void shouldPostAndGetArticlesWithErrorHandling() { + assertThatThrownBy(() -> { + restClient.get() + .uri(uriBase + "/articles/1234") + .retrieve() + .onStatus(status -> status.value() == 404, (request, response) -> { throw new ArticleNotFoundException(); }) + .body(new ParameterizedTypeReference<>() {}); + }).isInstanceOf(ArticleNotFoundException.class); + } + @Test void shouldPostAndPutAndGetArticles() { Article article = new Article(1, "How to use RestClient"); @@ -79,7 +130,7 @@ public class RestClientIntegrationTest { .contentType(MediaType.APPLICATION_JSON) .body(articleChanged) .retrieve() - .toBodilessEntity(); + .toBodilessEntity(); List
articles = restClient.get() .uri(uriBase + "/articles") @@ -104,11 +155,12 @@ public class RestClientIntegrationTest { .retrieve() .toBodilessEntity(); - List
articles = restClient.get() + ResponseEntity entity = restClient.get() .uri(uriBase + "/articles") + .accept(MediaType.APPLICATION_JSON) .retrieve() - .body(new ParameterizedTypeReference<>() {}); + .toBodilessEntity(); - assertThat(articles).isEqualTo(List.of()); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204)); } } From 8ffbb095da59585553a065426dc43ea227cf9a75 Mon Sep 17 00:00:00 2001 From: Bhaskar Ghosh Dastidar Date: Tue, 10 Oct 2023 01:29:52 +0530 Subject: [PATCH 126/135] [BAEL-6955] finalization deprcation (#14932) Co-authored-by: Bhaskar --- core-java-modules/core-java-18/README.md | 0 core-java-modules/core-java-18/pom.xml | 55 +++++++++++++++++++ .../FinalizationExamples.java | 27 +++++++++ .../MyCleanerResourceClass.java | 48 ++++++++++++++++ .../MyCloseableResourceClass.java | 25 +++++++++ .../MyFinalizableResourceClass.java | 24 ++++++++ .../core-java-18/src/main/resources/file.txt | 1 + .../FinalizationCloseableCleanerUnitTest.java | 36 ++++++++++++ 8 files changed, 216 insertions(+) create mode 100644 core-java-modules/core-java-18/README.md create mode 100644 core-java-modules/core-java-18/pom.xml create mode 100644 core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java create mode 100644 core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java create mode 100644 core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java create mode 100644 core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java create mode 100644 core-java-modules/core-java-18/src/main/resources/file.txt create mode 100644 core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java diff --git a/core-java-modules/core-java-18/README.md b/core-java-modules/core-java-18/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java-modules/core-java-18/pom.xml b/core-java-modules/core-java-18/pom.xml new file mode 100644 index 0000000000..7af6258497 --- /dev/null +++ b/core-java-modules/core-java-18/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + core-java-18 + core-java-18 + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.release} + --enable-preview + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + 1 + + + + org.apache.maven.surefire + surefire-api + ${surefire.plugin.version} + + + + + + + + 18 + 18 + 18 + 3.0.0-M5 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java new file mode 100644 index 0000000000..3ff77c37d6 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java @@ -0,0 +1,27 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.IOException; + +public class FinalizationExamples { + FileInputStream fis = null; + + public void readFileOperationWithFinalization() throws IOException { + try { + fis = new FileInputStream("input.txt"); + // perform operation on the file + System.out.println(fis.readAllBytes().length); + + } finally { + if (fis != null) + fis.close(); + } + } + + public void readFileOperationWithTryWith() throws IOException { + try (FileInputStream fis = new FileInputStream("input.txt")) { + // perform operations + System.out.println(fis.readAllBytes().length); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java new file mode 100644 index 0000000000..1dcdd216cb --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java @@ -0,0 +1,48 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.lang.ref.Cleaner; + +public class MyCleanerResourceClass implements AutoCloseable { + private static Resource resource; + + private static final Cleaner cleaner = Cleaner.create(); + private final Cleaner.Cleanable cleanable; + + public MyCleanerResourceClass() { + resource = new Resource(); + this.cleanable = cleaner.register(this, new CleaningState()); + } + + public void useResource() { + // using the resource here + resource.use(); + } + + @Override + public void close() { + // perform actions to close all underlying resources + this.cleanable.clean(); + } + + static class CleaningState implements Runnable { + CleaningState() { + // constructor + } + + @Override + public void run() { + // some cleanup action + System.out.println("Cleanup done"); + } + } + + static class Resource { + void use() { + System.out.println("Using the resource"); + } + + void close() { + System.out.println("Cleanup done"); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java new file mode 100644 index 0000000000..b11cb4e49e --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java @@ -0,0 +1,25 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyCloseableResourceClass implements AutoCloseable { + + private final FileInputStream fis; + + public MyCloseableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + @Override + public void close() throws IOException { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java new file mode 100644 index 0000000000..a2c6a123b4 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java @@ -0,0 +1,24 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyFinalizableResourceClass { + private FileInputStream fis; + + public MyFinalizableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + + @Override + protected void finalize() throws Throwable { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/resources/file.txt b/core-java-modules/core-java-18/src/main/resources/file.txt new file mode 100644 index 0000000000..af27ff4986 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/resources/file.txt @@ -0,0 +1 @@ +This is a test file. \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java new file mode 100644 index 0000000000..22ff228227 --- /dev/null +++ b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.finalization_closeable_cleaner; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +public class FinalizationCloseableCleanerUnitTest { + + @Test + public void givenMyFinalizationResource_whenUsingFinalize_thenShouldClean() { + assertDoesNotThrow(() -> { + MyFinalizableResourceClass mfr = new MyFinalizableResourceClass(); + mfr.getByteLength(); + }); + } + @Test + public void givenMyCleanerResource_whenUsingCleanerAPI_thenShouldClean() { + assertDoesNotThrow(() -> { + try (MyCleanerResourceClass myCleanerResourceClass = new MyCleanerResourceClass()) { + myCleanerResourceClass.useResource(); + } + }); + } + + @Test + public void givenCloseableResource_whenUsingTryWith_thenShouldClose() throws IOException { + int length = 0; + try (MyCloseableResourceClass mcr = new MyCloseableResourceClass()) { + length = mcr.getByteLength(); + } + Assert.assertEquals(20, length); + } +} From 150efcec722ddc89b098202593f0015ab86dde3b Mon Sep 17 00:00:00 2001 From: ACHRAF TAITAI <43656331+achraftt@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:01:20 +0200 Subject: [PATCH 127/135] BAEL-6984: Deprecate URL Public Constructors in Java 20 (#14934) --- .../baeldung/networking/url/UrlUnitTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java index 87d9d7a620..ca04263689 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java @@ -2,10 +2,15 @@ package com.baeldung.networking.url; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import org.apache.http.client.utils.URIBuilder; @@ -149,4 +154,24 @@ public class UrlUnitTest { assertEquals("http://baeldung.com:9090/articles?topic=java&version=8", url.toString()); } + @Test + public void givenURI_whenConvertingToURL_thenCorrect() throws IOException, URISyntaxException { + String aURIString = "http://courses.baeldung.com"; + URI uri = new URI(aURIString); + URL url = uri.toURL(); + assertNotNull(url); + assertEquals(aURIString, url.toString()); + } + + @Test + public void givenPath_whenConvertingToURIAndThenURL_thenCorrect() throws IOException, URISyntaxException { + String finalPath = "file:/D:/baeldung/java-url"; + Path path = Paths.get("/baeldung/java-url"); + URI uri = path.toUri(); + URL url = uri.toURL(); + assertNotNull(url); + // Adapt the finalPath value to match your own path + // assertEquals(finalPath, url.toString()); + } + } \ No newline at end of file From 3bd2e7eb3ef9451ce624723f92194d3c293be51e Mon Sep 17 00:00:00 2001 From: Anton Dalagan Date: Mon, 9 Oct 2023 22:05:03 +0200 Subject: [PATCH 128/135] Bael 6962 convert double to float in java (#14936) * Commit 1 - Anton Dalagan Code for Evaluation article. Contains Unit tests, domain class, and App main method. * BAEL-6962 - Created unit test, and updated pom.xml * BAEL-6962 - Removed files unrelated to the article * BAEL-6962 - Added a declartions for float and double in diff class. Updated unit tests. * BAEL-6962 - Made changes into the unit tests. Removed printlns, and updated isinstance with assertequals --- .../FloatDoubleConversionsTest.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java index 10e9fd4c36..9c6b01e9de 100644 --- a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java @@ -9,25 +9,21 @@ public class FloatDoubleConversionsTest { public void whenDoubleType_thenFloatTypeSuccess(){ double interestRatesYearly = 13.333333333333334; float interest = (float) interestRatesYearly; - System.out.println(interest); //13.333333 - Assert.assertTrue(Float.class.isInstance(interest));//true + Assert.assertEquals(13.333333f, interest, 0.000004f); Double monthlyRates = 2.111111111111112; float rates = monthlyRates.floatValue(); - System.out.println(rates); //2.1111112 - Assert.assertTrue(Float.class.isInstance(rates));//true + Assert.assertEquals(2.1111112f, rates, 0.00000013); } @Test public void whenFloatType_thenDoubleTypeSuccess(){ float gradeAverage =2.05f; double average = gradeAverage; - System.out.println(average); //2.049999952316284 - Assert.assertTrue(Double.class.isInstance(average));//true + Assert.assertEquals(2.05, average, 0.06); Float monthlyRates = 2.1111112f; Double rates = monthlyRates.doubleValue(); - System.out.println(rates); //2.1111112 - Assert.assertTrue(Double.class.isInstance(rates));//true + Assert.assertEquals(2.11111112, rates, 0.0000002);//true } } From a3148b3dd29e283df74e9f47a83826598732ca45 Mon Sep 17 00:00:00 2001 From: Bhaskar Ghosh Dastidar Date: Tue, 10 Oct 2023 01:38:57 +0530 Subject: [PATCH 129/135] [BAEL-7035] improvement to value based class (#14938) Co-authored-by: Bhaskar --- .../main/java/com/baeldung/value_based_class/Point.java | 5 +++++ .../value_based_class/ValueBasedClassUnitTest.java | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java index 13e2238274..a3055985af 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java @@ -30,6 +30,11 @@ public final class Point { return new Point(x, y, z); } + @Override + public String toString() { + return "Point{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; + } + @Override public boolean equals(Object other) { if (other == null || getClass() != other.getClass()) diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java index 781f368982..fe031a652f 100644 --- a/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java @@ -1,14 +1,17 @@ package com.baeldung.value_based_class; +import java.util.ArrayList; +import java.util.List; + import org.junit.Assert; import org.junit.Test; public class ValueBasedClassUnitTest { @Test public void givenAutoboxedAndPrimitive_whenCompared_thenReturnEquals() { - int primitive_a = 125; - Integer obj_a = 125; // this is autoboxed - Assert.assertSame(primitive_a, obj_a); + List list = new ArrayList<>(); + list.add(1); // this is autoboxed + Assert.assertEquals(list.get(0), Integer.valueOf(1)); } @Test From a74415a7c7698e6412a7573bbc02062741627fc6 Mon Sep 17 00:00:00 2001 From: Kai Yuan Date: Tue, 10 Oct 2023 02:08:53 +0200 Subject: [PATCH 130/135] [rm-linebreaks-inFile] How to Remove Line Breaks From a File in Java (#14917) --- .../RemoveLinebreaksUnitTest.java | 72 +++++++++++++++++++ .../src/test/resources/multiple-line-1.txt | 6 ++ .../src/test/resources/multiple-line-2.txt | 4 ++ 3 files changed, 82 insertions(+) create mode 100644 core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java create mode 100644 core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt create mode 100644 core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt diff --git a/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java new file mode 100644 index 0000000000..7cfc7ede79 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.rmlinebreaks; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class RemoveLinebreaksUnitTest { + + private Path file1Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-1.txt").toURI()); + } + + private Path file2Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-2.txt").toURI()); + } + + @Test + void whenRemovingLineSeparatorFromFile1_thenGetTheExpectedResult() throws Exception { + String content = Files.readString(file1Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertEquals("A, B, C, D, E, F", result); + } + + @Test + void whenRemovingLineSeparatorFromFile2_thenNotGetTheExpectedResult() throws Exception { + String content = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertNotEquals("A, B, C, D, E, F", result); // <-- NOT equals assertion! + } + + @Test + void whenRemovingAllLinebreaks_thenGetTheExpectedResult() throws Exception { + String content1 = Files.readString(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + String content2 = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result1 = content1.replace("\r", "").replace("\n", ""); + String result2 = content2.replace("\r", "").replace("\n", ""); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + + String resultReplaceAll = content2.replaceAll("[\\n\\r]", ""); + assertEquals("A, B, C, D, E, F", resultReplaceAll); + + } + + @Test + void whenUsingReadAllLinesAndJoin_thenGetExpectedResult() throws Exception { + List lines1 = Files.readAllLines(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + List lines2 = Files.readAllLines(file2Path(), StandardCharsets.UTF_8); + + String result1 = String.join("", lines1); + String result2 = String.join("", lines2); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt new file mode 100644 index 0000000000..42e87e734e --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt @@ -0,0 +1,6 @@ +A, + B, + C, + D, + E, + F diff --git a/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt new file mode 100644 index 0000000000..4fe5d5f4ed --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt @@ -0,0 +1,4 @@ +A, B, + C, + D, E, + F From 91b80094fc7aaad90d161934a7d3fc3322822fd6 Mon Sep 17 00:00:00 2001 From: timis1 <12120641+timis1@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:02:45 +0300 Subject: [PATCH 131/135] JAVA-25517 Upgrade spring-boot-bootstrap to Spring Boot 3 (#14896) --- spring-boot-modules/spring-boot-bootstrap/pom.xml | 15 ++++++++------- .../java/com/baeldung/config/SecurityConfig.java | 12 ++++++------ .../java/com/baeldung/persistence/model/Book.java | 10 +++++----- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/spring-boot-modules/spring-boot-bootstrap/pom.xml b/spring-boot-modules/spring-boot-bootstrap/pom.xml index 4ceae26f60..da16f79a2a 100644 --- a/spring-boot-modules/spring-boot-bootstrap/pom.xml +++ b/spring-boot-modules/spring-boot-bootstrap/pom.xml @@ -9,9 +9,10 @@ Demo project for Spring Boot - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -47,13 +48,12 @@ io.rest-assured rest-assured - ${rest-assured.version} test - javax.servlet - javax.servlet-api - ${servlet.version} + org.springframework.boot + spring-boot-starter-cloud-connectors + ${spring-boot-cloud-connectors.version} @@ -332,6 +332,7 @@ 4.0.0 Greenwich.RELEASE 1.0.0.RELEASE + 2.2.13.RELEASE \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java index ecb21cdf4b..c876e1c3d4 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java @@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; @Configuration @@ -12,12 +13,11 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.authorizeRequests() - .anyRequest() - .permitAll() - .and() - .csrf() - .disable(); + http.authorizeHttpRequests(expressionInterceptUrlRegistry -> + expressionInterceptUrlRegistry + .anyRequest() + .permitAll()) + .csrf(AbstractHttpConfigurer::disable); return http.build(); } } diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java index 6be27d4cf0..d599c64567 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java @@ -1,10 +1,10 @@ package com.baeldung.persistence.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Book { From 25263d41258b6ce022b5e9577af618b5cb8ee896 Mon Sep 17 00:00:00 2001 From: Thiago dos Santos Hora Date: Tue, 10 Oct 2023 17:13:55 +0200 Subject: [PATCH 132/135] NO-JIRA: Fix docker test for shardingphere @thiagohora (#14704) * [BAEL-4897] Shardingshere * [BAEL-4897] Fixes * NO-JIRA: Fix docker test for shardingphere --- .../OrderServiceManualTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java new file mode 100644 index 0000000000..895dd52afb --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java @@ -0,0 +1,90 @@ +package com.baeldung.shardingsphere; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import java.util.List; + + +/** + * This Manual test requires: Docker service running. + */ +@Testcontainers +@SpringBootTest +class OrderServiceManualTest { + + @Container + static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds0") + .withUsername("test") + .withPassword("test"); + + @Container + static MySQLContainer mySQLContainer2 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds1") + .withUsername("test") + .withPassword("test"); + + static { + mySQLContainer2.setPortBindings(List.of("13307:3306")); + mySQLContainer1.setPortBindings(List.of("13306:3306")); + } + @Autowired + private OrderService orderService; + + @Autowired + private OrderRepository orderRepository; + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); + } + + @Test + void shouldFindOrderInCorrectShard() { + // given + Order order1 = new Order(1L, 1L, BigDecimal.TEN, Status.PROCESSING, LocalDate.now(), "123 Main St"); + Order order2 = new Order(2L, 2L, BigDecimal.valueOf(12.5), Status.SHIPPED, LocalDate.now(), "456 Main St"); + + // when + Order savedOrder1 = orderService.createOrder(order1); + Order savedOrder2 = orderService.createOrder(order2); + + // then + // Assuming the sharding strategy is based on the order id, data for order1 should be present only in ds0 + // and data for order2 should be present only in ds1 + Assertions.assertThat(orderService.getOrder(savedOrder1.getOrderId())).isEqualTo(savedOrder1); + Assertions.assertThat(orderService.getOrder(savedOrder2.getOrderId())).isEqualTo(savedOrder2); + + // Verify that the orders are not present in the wrong shards. + // You would need to implement these methods in your OrderService. + // They should use a JdbcTemplate or EntityManager to execute SQL directly against each shard. + Assertions.assertThat(assertOrderInShard(savedOrder1, mySQLContainer2)).isTrue(); + Assertions.assertThat(assertOrderInShard(savedOrder2, mySQLContainer1)).isTrue(); + } + + private boolean assertOrderInShard(Order order, MySQLContainer container) { + try (Connection conn = DriverManager.getConnection(container.getJdbcUrl(), container.getUsername(), container.getPassword())) { + PreparedStatement stmt = conn.prepareStatement("SELECT * FROM `order` WHERE order_id = ?"); + stmt.setLong(1, order.getOrderId()); + ResultSet rs = stmt.executeQuery(); + return rs.next(); + } catch (SQLException ex) { + throw new RuntimeException("Error querying order in shard", ex); + } + } +} From d5b2f61ea084112760fcb8d8ec5ba22cb4f754b7 Mon Sep 17 00:00:00 2001 From: lucaCambi77 Date: Wed, 11 Oct 2023 03:35:10 +0200 Subject: [PATCH 133/135] BAEL-6913 - Rotate array in java (#14861) * feat: rotate array in java * fix: When to when --- .../algorithms/rotatearray/RotateArray.java | 102 ++++++++++++++ .../rotatearray/RotateArrayUnitTest.java | 124 ++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java create mode 100644 algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java new file mode 100644 index 0000000000..36490d4899 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java @@ -0,0 +1,102 @@ +package com.baeldung.algorithms.rotatearray; + +/** + * To speed up the rotation, we narrow k rotations to the remainder of k divided by the array length, or k module the array length. + * Therefore, a large rotation number will be translated into the relative smallest rotation. + * All solutions replace the original array, although they might use an extra array to compute the rotation. + */ +public class RotateArray { + + private RotateArray() { + throw new IllegalStateException("Rotate array algorithm utility methods class"); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void bruteForce(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + int temp; + int previous; + for (int i = 0; i < k; i++) { + previous = arr[arr.length - 1]; + for (int j = 0; j < arr.length; j++) { + temp = arr[j]; + arr[j] = previous; + previous = temp; + } + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void withExtraArray(int[] arr, int k) { + checkInvalidInput(arr, k); + + int[] extraArray = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + extraArray[(i + k) % arr.length] = arr[i]; + } + System.arraycopy(extraArray, 0, arr, 0, arr.length); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void cyclicReplacement(int[] arr, int k) { + checkInvalidInput(arr, k); + + k = k % arr.length; + int count = 0; + for (int start = 0; count < arr.length; start++) { + int current = start; + int prev = arr[start]; + do { + int next = (current + k) % arr.length; + int temp = arr[next]; + arr[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void reverse(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + reverse(arr, 0, arr.length - 1); + reverse(arr, 0, k - 1); + reverse(arr, k, arr.length - 1); + } + + private static void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } + + private static void checkInvalidInput(int[] arr, int rotation) { + if (rotation < 1 || arr == null) + throw new IllegalArgumentException("Rotation must be greater than zero or array must be not null"); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java new file mode 100644 index 0000000000..4a98acdb75 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java @@ -0,0 +1,124 @@ +package com.baeldung.algorithms.rotatearray; + +import static com.baeldung.algorithms.rotatearray.RotateArray.bruteForce; +import static com.baeldung.algorithms.rotatearray.RotateArray.cyclicReplacement; +import static com.baeldung.algorithms.rotatearray.RotateArray.reverse; +import static com.baeldung.algorithms.rotatearray.RotateArray.withExtraArray; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class RotateArrayUnitTest { + + private final int[] arr = { 1, 2, 3, 4, 5, 6 }; + private final int rotationLtArrayLength = 1; + private final int rotationGtArrayLength = arr.length + 2; + private final int[] ltArrayLengthRotation = { 6, 1, 2, 3, 4, 5 }; + private final int[] gtArrayLengthRotation = { 5, 6, 1, 2, 3, 4 }; + + @Test + void givenInputArray_whenNoRotationOrEmptyArray_thenThrowIllegalArgumentException() { + final int noRotation = 0; + final int someRotation = arr.length - 1; + + assertThrows(IllegalArgumentException.class, () -> bruteForce(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(arr, noRotation)); + + assertThrows(IllegalArgumentException.class, () -> bruteForce(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(null, someRotation)); + } + + @Test + void givenInputArray_whenUseBruteForceRotationLtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationGtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationEqArrayLength_thenDoNothing() { + int[] expected = arr.clone(); + + bruteForce(arr, arr.length); + assertArrayEquals(expected, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationLtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationGtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayWithRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + withExtraArray(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationLtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationGtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + cyclicReplacement(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationLtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationGtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationEqArrayLength_thenDoNothing() { + + int[] clone = arr.clone(); + + reverse(arr, arr.length); + assertArrayEquals(clone, arr); + } +} From 1912c8c618831bc4cf58ce52c6e53d95365c1753 Mon Sep 17 00:00:00 2001 From: Gaetano Piazzolla Date: Wed, 11 Oct 2023 09:14:39 +0200 Subject: [PATCH 134/135] JAVA-22296 | Upgrade spring-cloud-modules to JDK 17: Chunk 4 - integration tests fix (#14907) spring-cloud-contract, spring-cloud-data-flow --- pom.xml | 1 + .../spring-cloud-contract/pom.xml | 13 +++++++--- .../spring-cloud-contract-consumer/pom.xml | 24 ++++++++++++------- .../spring-cloud-contract-producer/pom.xml | 22 ++++++++++++----- ...aFlowServerApplicationIntegrationTest.java | 6 +++++ 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 6853b10587..197074c455 100644 --- a/pom.xml +++ b/pom.xml @@ -1005,6 +1005,7 @@ spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract + spring-cloud-modules/spring-cloud-data-flow spring-cloud-modules/spring-cloud-netflix-feign spring-cloud-modules/spring-cloud-stream-starters spring-cloud-modules/spring-cloud-zuul-eureka-integration diff --git a/spring-cloud-modules/spring-cloud-contract/pom.xml b/spring-cloud-modules/spring-cloud-contract/pom.xml index 7a9c8c32cd..f2d0d1b5b0 100644 --- a/spring-cloud-modules/spring-cloud-contract/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/pom.xml @@ -41,28 +41,35 @@ org.springframework.cloud spring-cloud-contract-wiremock - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-contract-stub-runner - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-starter-contract-verifier - ${spring-cloud.version} + ${spring-cloud-contract.version} test + + org.codehaus.groovy + groovy + ${groovy.version} + 4.0.3 + 4.0.4 2.1.4.RELEASE 2.17.1 + 2.5.6 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml index 680e2e1795..a8c3337de5 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml @@ -16,6 +16,15 @@ + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-rest + + org.springframework.cloud spring-cloud-contract-wiremock @@ -26,20 +35,13 @@ spring-cloud-contract-stub-runner test - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-data-rest - com.baeldung.spring.cloud spring-cloud-contract-producer ${project.parent.version} test + io.rest-assured rest-assured @@ -50,6 +52,12 @@ + + + org.codehaus.groovy + groovy + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml index 35dd9596f7..eb80f8d3dd 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml @@ -16,19 +16,17 @@ - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - + org.springframework.boot spring-boot-starter-web + org.springframework.boot spring-boot-starter-data-rest + io.rest-assured rest-assured @@ -39,6 +37,18 @@ + + + org.springframework.cloud + spring-cloud-starter-contract-verifier + test + + + + org.codehaus.groovy + groovy + + @@ -46,7 +56,7 @@ org.springframework.cloud spring-cloud-contract-maven-plugin - 2.1.1.RELEASE + ${spring-cloud-contract.version} true com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java index 68f0db60eb..49eb255303 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.session.data.redis.config.ConfigureRedisAction; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.test.context.junit4.SpringRunner; @@ -39,5 +40,10 @@ public class DataFlowServerApplicationIntegrationTest { return factory; } + + @Bean + public static ConfigureRedisAction configureRedisAction() { + return ConfigureRedisAction.NO_OP; + } } } From 03a3587560110f76117fbb97631224df94be3ad2 Mon Sep 17 00:00:00 2001 From: Gaetano Piazzolla Date: Wed, 11 Oct 2023 10:04:44 +0200 Subject: [PATCH 135/135] JAVA-25157 | minor fixes (#14915) --- .../spring-boot-keycloak/pom.xml | 2 +- ...ingBoot.java => SpringBootKeycloakApp.java} | 5 ++--- .../KeycloakContextIntegrationTest.java | 3 +-- .../swaggerkeycloak/GlobalSecurityConfig.java | 18 +++++++++++------- 4 files changed, 15 insertions(+), 13 deletions(-) rename spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/{SpringBoot.java => SpringBootKeycloakApp.java} (80%) diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index bada9ab52d..13339c9de1 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -102,7 +102,7 @@ - com.baeldung.keycloak.SpringBoot + com.baeldung.keycloak.SpringBootKeycloakApp 4.0.0 1.6.3 2.5.0 diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java similarity index 80% rename from spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java rename to spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java index 90d7e774a4..a6f978fb3f 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java @@ -6,11 +6,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication - -public class SpringBoot { +public class SpringBootKeycloakApp { public static void main(String[] args) { - SpringApplication.run(SpringBoot.class, args); + SpringApplication.run(SpringBootKeycloakApp.class, args); } @Bean diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java index 336c8364aa..116516acfe 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java +++ b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java @@ -4,10 +4,9 @@ import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.baeldung.keycloak.SpringBoot; @ExtendWith(SpringExtension.class) -@SpringBootTest(classes = { SpringBoot.class }) +@SpringBootTest(classes = { SpringBootKeycloakApp.class }) public class KeycloakContextIntegrationTest { @Test diff --git a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java index 5c24368ce6..9a1bf547db 100644 --- a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java +++ b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java @@ -3,10 +3,11 @@ package com.baeldung.swaggerkeycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; @@ -24,16 +25,19 @@ public class GlobalSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .requestMatchers(HttpMethod.OPTIONS) + + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests((requests) -> requests.requestMatchers(HttpMethod.OPTIONS) .permitAll() .requestMatchers("/api/**") .authenticated() .anyRequest() - .permitAll(); - http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + .permitAll()); + + http.oauth2ResourceServer((oauth2) -> oauth2 + .jwt(Customizer.withDefaults()) + ); + return http.build(); }