You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/10/18 12:09:41 UTC
(juneau) branch master updated: Taller page tabs with a bold selected subtab, hex decoding in keychain find, and a fix for the console bus-trace redraw-order flake; clear Eclipse warnings in rest-client, server/microservice and marshall/views/console/petstore; fix or suppress the Sonar issues across modules; and stop the juneau-run history concurrent-append test from dropping writes during compaction.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new b8d5b91d2c Taller page tabs with a bold selected subtab, hex decoding in keychain find, and a fix for the console bus-trace redraw-order flake; clear Eclipse warnings in rest-client, server/microservice and marshall/views/console/petstore; fix or suppress the Sonar issues across modules; and stop the juneau-run history concurrent-append test from dropping writes during compaction.
b8d5b91d2c is described below
commit b8d5b91d2c4c364a257ca84cb59126cd8fd6e039
Author: James Bognar <ja...@apache.org>
AuthorDate: Sun Oct 18 08:09:32 2026 -0400
Taller page tabs with a bold selected subtab, hex decoding in keychain find, and a fix for the console bus-trace redraw-order flake; clear Eclipse warnings in rest-client, server/microservice and marshall/views/console/petstore; fix or suppress the Sonar issues across modules; and stop the juneau-run history concurrent-append test from dropping writes during compaction.
---
.../bean/jsonpatch/JsonPatchMarshaller_Test.java | 12 +-
.../org/apache/juneau/commons/bean/BeanMeta.java | 4 +-
.../juneau/commons/beanquery/InMemoryMatch.java | 6 +-
.../juneau/commons/beanquery/QueryProperty.java | 3 +
.../juneau/commons/http/SafePathTemplate.java | 3 +
.../juneau/commons/logging/LogRecordCapture.java | 6 +
.../commons/beanquery/SearchOperatorSet_Test.java | 5 +-
.../juneau/config/internal/ConfigMap_Test.java | 10 +-
.../marshall/jena/RdfStreamSerializerSession.java | 2 +-
...ParserSerializerSet_DefaultMediaTypes_Test.java | 2 +-
.../juneau/marshall/jena/RdfParser_Test.java | 4 +-
.../juneau/marshall/jena/RdfSerializer_Test.java | 16 +-
.../parser/MissingRequiredPropertyException.java | 3 +
.../org/apache/juneau/WriteOnlyColumns_Test.java | 3 +-
.../MissingRequiredProperty_Conversion_Test.java | 3 +-
...ParserSerializerSet_DefaultMediaTypes_Test.java | 2 +-
.../juneau/marshall/RecordComponentOrder_Test.java | 8 +-
.../MissingRequiredProperty_Formats_Test.java | 2 +-
.../apache/juneau/rest/server/Rest_Debug_Test.java | 2 +-
.../rest/server/VirtualThreadDispatch_Test.java | 4 +-
.../AuthFilterChain_GuardIntegration_Test.java | 2 +-
.../rest/server/auth/AuthFilterChain_Test.java | 4 +-
.../rest/server/servlet/RestServlet_Test.java | 6 +-
.../rest/test/client/ThirdPartyProxy_Test.java | 1 -
.../RestValidation_MissingProvider_Test.java | 4 +-
.../microservice/examples/AdminBoundary.java | 2 +-
.../microservice/examples/AdminBoundary_Test.java | 3 +
.../microservice/examples/DebugResource_Test.java | 1 +
.../microservice/jetty/JettyServerComponent.java | 6 +-
.../microservice/jetty/AllowHeader_Jetty_Test.java | 1 +
.../jetty/BusWebSocketCsrf_JettyIT.java | 13 +-
.../microservice/jetty/BusWebSocket_JettyIT.java | 3 +
.../jetty/CsrfBoundaryForwarded_JettyIT.java | 3 +
.../microservice/jetty/CsrfBoundary_JettyIT.java | 138 ++++----
.../ServletFilterRegistration_JettyMount_Test.java | 11 +-
.../microservice/tomcat/TomcatServerComponent.java | 2 +-
.../tomcat/BusWebSocketCsrf_TomcatIT.java | 21 +-
...ServletFilterRegistration_TomcatMount_Test.java | 11 +-
.../apache/juneau/microservice/Microservice.java | 6 +-
.../microservice/ServletFilterRegistration.java | 50 +--
.../ServletFilterRegistration_Test.java | 33 +-
.../petstore/console/PetstoreApiBoundary.java | 2 +-
.../apache/juneau/petstore/console/StoreRest.java | 6 +-
.../petstore/console/dev/CustomCardsRest.java | 3 +-
.../juneau/petstore/console/dev/DashboardRest.java | 6 +-
.../console/dev/InventoryGaugeCardType.java | 3 +
.../juneau/petstore/console/ops/GroomRuns.java | 19 +-
.../juneau/petstore/console/ops/JobsRest.java | 22 +-
.../juneau/petstore/console/orders/OrdersRest.java | 4 +-
.../console/pages/ChangesPageBuilders.java | 3 +
.../petstore/console/pages/DevPageBuilders.java | 3 +
.../petstore/console/pages/OpsPageBuilders.java | 3 +
.../petstore/console/pages/OrdersPageBuilders.java | 3 +
.../petstore/console/pages/PetsPageBuilders.java | 3 +
.../petstore/console/pages/StorePageBuilders.java | 3 +
.../petstore/console/pages/UsersPageBuilders.java | 3 +
.../juneau/petstore/console/pets/PetsRest.java | 3 +
.../juneau/petstore/console/users/UsersRest.java | 3 +-
.../org/apache/juneau/petstore/console/petstore.js | 55 +--
.../petstore/console/PetstoreAssets_Test.java | 2 +-
.../petstore/console/PetstoreFailLoud_Test.java | 3 +
.../petstore/console/PetstoreTwins_Test.java | 9 +-
.../browser/PetstoreConsoleWrites_BrowserTest.java | 3 +
.../browser/PetstoreOrderWizard_BrowserTest.java | 6 +-
.../browser/PetstoreTerminal_BrowserTest.java | 1 -
.../console/browser/PetstoreTestServer.java | 1 -
.../browser/PetstoreTreemap_BrowserTest.java | 4 +-
.../console/browser/PetstoreTwins_BrowserTest.java | 1 -
.../browser/PetstoreTypedConfirm_BrowserTest.java | 1 -
.../petstore/console/dev/DashboardRest_Test.java | 19 +-
.../console/dev/InventoryGaugeCardType_Test.java | 3 +-
.../console/dev/flavors/FlavorsRest_Test.java | 1 -
.../petstore/console/ops/GroomRuns_Test.java | 6 +
.../petstore/console/pets/PetsRest_Test.java | 1 -
.../petstore/marshall/PetPhotoParser_Test.java | 3 +-
.../src/test/js/petstore-browser.cjs | 2 +-
.../juneau/petstore/jetty/PetstoreJetty_Test.java | 29 +-
.../springboot/PetstoreSpringboot_Test.java | 2 +-
.../ApacheHc45TransportBuilder.java | 3 +
.../Hc45RedirectCredentialGuard.java | 5 +-
...sport_CallerClientRedirectCredentials_Test.java | 5 +-
.../client/ApacheHc45Transport_SsrfGuard_Test.java | 6 +-
...nsport_BuiltClientRedirectCredentials_Test.java | 2 +-
...sport_CallerClientRedirectCredentials_Test.java | 1 +
.../rest/client/ApacheHc5Transport_Edge_Test.java | 16 +-
.../client/ApacheHc5Transport_SsrfGuard_Test.java | 9 +-
.../client/classic/HttpClientBuilderSettings.java | 7 +
.../rest/client/classic/ResponseContent.java | 82 +++--
.../juneau/rest/client/classic/RestClient.java | 19 +-
.../juneau/rest/client/classic/RestRequest.java | 51 +--
.../client/classic/SsrfGuardConnectionManager.java | 19 +-
.../rest/client/classic/SsrfGuardMarker.java | 7 +-
.../classic/remote/RemoteMetadataException.java | 4 +-
.../client/classic/remote/RemoteProxyUtils.java | 2 +-
.../RestClient_AllowAddressRanges_Test.java | 9 +-
.../classic/RestClient_ConnectionManager_Test.java | 259 ++++++++++----
.../client/classic/RestClient_Coverage2_Test.java | 6 +-
.../client/classic/RestClient_SsrfGuard_Test.java | 48 ++-
.../classic/RestRequest_Rethrow_Coverage_Test.java | 4 +
.../remote/RemoteMetadataException_Test.java | 12 +
.../jetty/CredentialGuardingHttpRequest.java | 3 +
.../client/JettyHttpTransport_SsrfGuard_Test.java | 9 +-
.../jetty/CredentialGuardingHttpClient_Test.java | 5 +-
.../PolicyPinningSocketAddressResolver_Test.java | 2 +-
.../auth/McpAuthorizationCodeAcquirer_Test.java | 44 ++-
.../auth/McpClientRegistrationManager_Test.java | 5 +-
.../mcp/auth/McpDynamicClientRegistrar_Test.java | 9 +-
.../McpProtectedResourceMetadataClient_Test.java | 3 +-
.../client/mcp/auth/McpTokenProvider_Test.java | 3 +-
.../mcp/auth/WwwAuthenticateChallenge_Test.java | 22 +-
.../mcp/v20260728/McpClient_Coverage_Test.java | 33 +-
.../okhttp/OkHttpRedirectCredentialGuard.java | 5 +
.../juneau/rest/client/okhttp/OkHttpTransport.java | 8 +-
.../client/OkHttpTransport_PolicyPath_Test.java | 5 +-
.../OkHttpTransport_RedirectCredentials_Test.java | 5 +-
.../client/OkHttpTransport_SsrfGuard_Test.java | 64 ++--
.../.sonarlint/connectedMode.json | 5 +
.../rest/client/PolicyEnforcedRedirects.java | 3 +
.../juneau/rest/client/TransportRequest.java | 2 +-
.../rest/client/PolicyEnforcedRedirects_Test.java | 2 +-
.../client/RestClient_AllowAddressRanges_Test.java | 14 +-
.../http/classic/header/BasicCsvHeader_Test.java | 6 +-
.../http/classic/header/BasicDateHeader_Test.java | 4 +-
.../classic/header/BasicIntegerHeader_Test.java | 3 +-
.../http/classic/header/BasicLongHeader_Test.java | 3 +-
.../classic/response/BasicHttpException_Test.java | 5 +-
.../classic/response/BasicHttpResponse_Test.java | 5 +-
.../classic/response/ClassicResponse_Test.java | 10 +-
.../apache/juneau/http/remote/RemoteUrlPolicy.java | 48 ++-
.../apache/juneau/rest/mock/MockRestClient.java | 2 +-
.../juneau/rest/mock/classic/MockRestClient.java | 2 +-
.../org/apache/juneau/rest/mock/NoTrace_Test.java | 24 +-
.../rest/mock/RestDebugFinishContainment_Test.java | 2 +-
.../saml/SamlAssertionValidator_Metadata_Test.java | 7 +-
.../SamlAssertionValidator_Rejections_Test.java | 35 +-
.../saml/SamlMetadataResolvers_Signed_Test.java | 7 +-
.../bus/websocket/BusWebSocketConfigurator.java | 5 +-
.../server/bus/websocket/BusWebSocketEndpoint.java | 13 +-
.../rest/server/bus/websocket/BusWebSockets.java | 6 +
.../rest/server/bus/websocket/WsFrameSink.java | 7 +-
.../rest/server/bus/websocket/BusFixture.java | 1 -
.../websocket/BusWebSocketConfigurator_Test.java | 2 +-
.../bus/websocket/BusWebSocketEndpoint_Test.java | 12 +-
.../server/bus/websocket/BusWebSockets_Test.java | 4 +-
.../server/bus/websocket/WsFrameSink_Test.java | 2 +-
.../apache/juneau/rest/server/bus/BusFrames.java | 25 +-
.../apache/juneau/rest/server/bus/BusPolicy.java | 3 +
.../apache/juneau/rest/server/bus/BusStream.java | 4 +-
.../apache/juneau/rest/server/bus/ServerBus.java | 56 +--
.../juneau/rest/server/bus/UpstreamHandler.java | 3 +
.../juneau/rest/server/bus/package-info.java | 4 +-
.../server/bus/BusEventsMixin_Session_Test.java | 8 +-
.../juneau/rest/server/bus/BusFrames_Test.java | 10 +-
.../juneau/rest/server/bus/BusPolicy_Test.java | 58 ++--
.../juneau/rest/server/bus/ServerBus_Test.java | 27 +-
.../juneau/rest/server/bus/SseFrameSink_Test.java | 3 +
.../.sonarlint/connectedMode.json | 5 +
.../freemarker/console/AssetUrlMethodModel.java | 2 +-
.../freemarker/console/BadgeDirectiveModel.java | 12 +-
.../freemarker/console/BridgeDirectiveModel.java | 3 +
.../view/freemarker/console/CardBusAttrs.java | 10 +-
.../freemarker/console/CardDirectiveModel.java | 11 +-
.../server/view/freemarker/console/CardSpec.java | 3 +-
.../view/freemarker/console/ChartCardType.java | 14 +-
.../server/view/freemarker/console/ChartDef.java | 14 +-
.../view/freemarker/console/ChoiceSection.java | 3 +
.../freemarker/console/ConsoleDirectiveModel.java | 3 +-
.../freemarker/console/ConsoleFreemarkerMixin.java | 9 +-
.../console/ConsoleTemplateValidator.java | 16 +-
.../view/freemarker/console/DashboardSpec.java | 8 +-
.../view/freemarker/console/DataSourceDef.java | 19 +-
.../freemarker/console/DatatablesCardType.java | 28 +-
.../view/freemarker/console/JobLogCardType.java | 7 +-
.../server/view/freemarker/console/Markers.java | 6 +-
.../freemarker/console/NodeDirectiveModel.java | 4 +
.../view/freemarker/console/PageCapture.java | 15 +-
.../server/view/freemarker/console/PageSpec.java | 25 +-
.../view/freemarker/console/PersistSpec.java | 3 +
.../rest/server/view/freemarker/console/Rail.java | 4 +-
.../view/freemarker/console/RangeSection.java | 5 +-
.../server/view/freemarker/console/Section.java | 5 +-
.../view/freemarker/console/TerminalCardType.java | 7 +-
.../freemarker/console/ThemeDirectiveModel.java | 7 +-
.../freemarker/console/TokenDirectiveModel.java | 3 +-
.../freemarker/console/ToolkitPackRegistry.java | 9 +-
.../freemarker/console/TopicDirectiveModel.java | 3 +
.../view/freemarker/console/AssetUrl_Test.java | 13 +-
.../freemarker/console/BridgeDirective_Test.java | 3 -
.../console/CardAssetDependencies_Test.java | 5 +-
.../view/freemarker/console/CardBusAttrs_Test.java | 9 +-
.../freemarker/console/CardDirective_Bus_Test.java | 2 -
.../view/freemarker/console/CardRef_Test.java | 1 -
.../freemarker/console/CardRequirements_Test.java | 7 +-
.../view/freemarker/console/CardSpec_Bus_Test.java | 11 +-
.../view/freemarker/console/CardSpec_Test.java | 3 +-
.../view/freemarker/console/ChartDef_Test.java | 142 +++++---
.../freemarker/console/ChartDef_Treemap_Test.java | 4 +-
.../freemarker/console/ConsoleDirective_Test.java | 62 +---
.../ConsoleFreemarkerMixin_CardType_Test.java | 10 +-
.../console/ConsoleFreemarkerMixin_Test.java | 13 +-
.../console/ConsoleTemplateValidator_Test.java | 14 +-
.../freemarker/console/DashboardSpec_Test.java | 9 +-
.../freemarker/console/DataSourceDef_Test.java | 6 +-
.../console/DatatablesCardType_Test.java | 104 ++++--
.../view/freemarker/console/Decorators_Test.java | 9 +-
.../view/freemarker/console/Derived_Test.java | 20 +-
.../freemarker/console/JobLogCard_Parity_Test.java | 1 -
.../freemarker/console/PageCapture_Bus_Test.java | 12 +-
.../freemarker/console/PageCapture_Merge_Test.java | 2 +-
.../console/PageSpec_BadgesFacts_Test.java | 18 +-
.../console/PageSpec_BrowserCorpus_Test.java | 3 +
.../view/freemarker/console/PageSpec_Bus_Test.java | 30 +-
.../freemarker/console/PageSpec_Cards_Test.java | 135 +++++---
.../console/PageSpec_Dashboard_Test.java | 10 +-
.../freemarker/console/PageSpec_Data_Test.java | 15 +-
.../freemarker/console/PageSpec_Merge_Test.java | 2 -
.../freemarker/console/PageSpec_Parity_Test.java | 6 +-
.../view/freemarker/console/PageSpec_Test.java | 44 ++-
.../freemarker/console/PageSpec_View_Test.java | 9 +-
.../view/freemarker/console/PersistSpec_Test.java | 24 +-
.../console/SameOriginPath_Corpus_Test.java | 3 +-
.../view/freemarker/console/Section_Test.java | 3 +-
.../freemarker/console/TerminalCardType_Test.java | 4 +-
.../console/TerminalCard_Parity_Test.java | 9 +-
.../console/ToolkitPackRegistry_Test.java | 57 ++--
.../freemarker/console/TopicDirective_Test.java | 1 -
.../src/test/resources/adopter-static/js/probe.js | 2 +-
.../resources/golden/theme-override/foundry.txt | 2 +-
.../test/resources/golden/theme-override/jrm.txt | 2 +-
.../resources/golden/theme-override/leaf-alias.txt | 2 +-
.../test/resources/golden/theme-override/ssc.txt | 2 +-
.../juneau/rest/server/console/BridgeDecl.java | 7 +-
.../rest/server/console/BusWiringValidator.java | 32 +-
.../juneau/rest/server/console/CardSource.java | 6 +-
.../rest/server/console/CardTypeHandler.java | 6 +
.../rest/server/console/CardTypeRegistry.java | 7 +-
.../juneau/rest/server/console/HtmlCardType.java | 3 +-
.../juneau/rest/server/console/Subscription.java | 3 +-
.../apache/juneau/rest/server/console/Theme.java | 5 +
.../apache/juneau/rest/server/console/Topics.java | 5 +-
.../rest/server/console/data/SeriesAggregator.java | 21 +-
.../rest/server/console/data/SeriesSource.java | 3 +
.../server/console/test/AssetResolutionAssert.java | 11 +-
.../resources/org/apache/juneau/console/chrome.css | 19 +-
.../org/apache/juneau/console/juneau-badges.js | 2 +-
.../org/apache/juneau/console/juneau-charts.js | 374 ++++++++++++---------
.../org/apache/juneau/console/juneau-console.js | 2 +-
.../org/apache/juneau/console/juneau-joblog.js | 2 +-
.../apache/juneau/console/juneau-theme-gray.css | 5 +
.../juneau/console/juneau-theme-light-brown.css | 5 +
.../juneau/console/juneau-theme-light-red.css | 5 +
.../apache/juneau/console/juneau-theme-open.css | 5 +
.../org/apache/juneau/console/juneau-theme-red.css | 5 +
.../rest/server/console/BridgeDecl_Test.java | 18 +-
.../server/console/BusWiringValidator_Test.java | 3 +-
.../rest/server/console/CardSource_Test.java | 1 -
.../rest/server/console/CardTypeRegistry_Test.java | 20 +-
.../server/console/ConsoleChromeMixin_Test.java | 33 +-
.../rest/server/console/DarkThemeCss_Test.java | 5 +-
.../rest/server/console/SchemeHead_Test.java | 17 +-
.../rest/server/console/StockThemeCss_Test.java | 2 +-
.../rest/server/console/Subscription_Test.java | 12 +-
.../server/console/Theme_DarkChannel_Test.java | 3 +-
.../rest/server/console/Theme_Gray_Test.java | 4 +-
.../rest/server/console/Theme_LightBrown_Test.java | 4 +-
.../rest/server/console/Theme_LightRed_Test.java | 4 +-
.../juneau/rest/server/console/Theme_Red_Test.java | 4 +-
.../juneau/rest/server/console/TopicDecl_Test.java | 33 +-
.../juneau/rest/server/console/Topics_Test.java | 3 +-
.../server/console/data/SeriesSource_Test.java | 2 +-
.../console/test/PageContractAssert_Bus_Test.java | 3 +-
.../test/resources/golden/chrome-css/default.txt | 2 +-
.../src/test/resources/golden/chrome-css/gray.txt | 4 +-
.../resources/golden/chrome-css/light-brown.txt | 4 +-
.../test/resources/golden/chrome-css/light-red.txt | 4 +-
.../src/test/resources/golden/chrome-css/open.txt | 2 +-
.../src/test/resources/golden/chrome-css/red.txt | 4 +-
.../management/logging/Log4j2LogBackend_Test.java | 1 +
.../rest/server/mcp/v20250618/McpWire_Test.java | 6 +-
.../rest/server/mcp/AbstractMcpRestServlet.java | 3 +
.../server/reactive/ReactiveResponseProcessor.java | 20 +-
.../ReactiveResponseProcessor_Adapter_Test.java | 3 +
.../rest/server/csrf/CsrfBoundary_SpringIT.java | 6 +-
.../rest/server/terminal/bus/TerminalNudges.java | 10 +-
.../server/terminal/bus/TerminalNudges_Test.java | 61 ++--
.../src/test/js/terminal-input-browser.cjs | 33 +-
.../rest/server/terminal/FileTerminalSource.java | 19 +-
.../rest/server/terminal/MemoryTerminalSource.java | 14 +-
.../juneau/rest/server/terminal/TerminalChunk.java | 3 +
.../juneau/rest/server/terminal/TerminalDef.java | 8 +-
.../rest/server/terminal/TerminalEndpoints.java | 2 +-
.../rest/server/terminal/TerminalProcess.java | 72 ++--
.../org/apache/juneau/terminal/juneau-terminal.js | 128 ++++---
.../terminal/FileTerminalSourceNudge_Test.java | 5 +-
.../server/terminal/FileTerminalSource_Test.java | 1 -
.../server/terminal/MemoryTerminalSource_Test.java | 3 +-
.../server/terminal/TerminalProcessInput_Test.java | 3 +
.../server/terminal/TerminalProcessNudge_Test.java | 3 +
.../rest/server/terminal/TerminalProcess_Test.java | 11 +-
.../src/test/js/terminal-browser.cjs | 87 ++---
.../src/test/js/terminal-smoke.cjs | 10 +-
.../src/test/js/terminal.cjs | 74 ++--
.../apache/juneau/rest/server/views/AsyncJob.java | 2 +-
.../apache/juneau/rest/server/views/BadgeDef.java | 3 +
.../apache/juneau/rest/server/views/Column.java | 3 +-
.../juneau/rest/server/views/FileLineIndex.java | 15 +-
.../rest/server/views/FileRunViewSource.java | 9 +-
.../juneau/rest/server/views/JobKeyLedger.java | 6 +-
.../juneau/rest/server/views/JobLogChecks.java | 6 +-
.../juneau/rest/server/views/JobLogRegion.java | 3 +
.../apache/juneau/rest/server/views/QuickStat.java | 3 +
.../juneau/rest/server/views/RibbonItem.java | 12 +-
.../juneau/rest/server/views/RunViewDef.java | 4 +
.../juneau/rest/server/views/RunViewLog.java | 2 +-
.../juneau/rest/server/views/RunViewPage.java | 4 +-
.../juneau/rest/server/views/RunViewSource.java | 3 +
.../apache/juneau/rest/server/views/TableSpec.java | 6 +-
.../org/apache/juneau/views/juneau-config.js | 16 +-
.../org/apache/juneau/views/juneau-data.js | 328 ++++++++++--------
.../org/apache/juneau/views/juneau-helpers.js | 2 +-
.../org/apache/juneau/views/juneau-regions.js | 4 +-
.../org/apache/juneau/views/juneau-renders.js | 3 +-
.../org/apache/juneau/views/juneau-ribbon.js | 12 +-
.../org/apache/juneau/views/juneau-run-view.js | 2 +-
.../org/apache/juneau/views/juneau-urlstate.js | 23 +-
.../org/apache/juneau/views/juneau-views.js | 152 +++++----
.../server/views/AsyncJobsMixin_Serving_Test.java | 3 +
.../juneau/rest/server/views/BadgeDef_Test.java | 3 +-
.../rest/server/views/ChromeCss_NavRules_Test.java | 6 +-
.../views/Column_DisplayProperties_Test.java | 6 +-
.../rest/server/views/ConsoleBrowserFixture.java | 6 +-
.../server/views/ConsoleBusTrace_BrowserTest.java | 26 +-
.../rest/server/views/ConsoleCards_Shell_Test.java | 4 +
.../server/views/ConsoleChartsOptions_Test.java | 4 +-
.../views/ConsoleCustomCard_BrowserTest.java | 9 +-
.../views/ConsoleDatatablesCard_BrowserTest.java | 4 +-
.../views/ConsoleHtmlCardSanitize_BrowserTest.java | 2 +-
.../rest/server/views/ConsoleJobLog_Test.java | 4 +
.../views/ConsoleLoudFailure_BrowserTest.java | 4 +-
.../server/views/CsrfBoundary_BrowserTest.java | 3 +
.../rest/server/views/FileRunViewSource_Test.java | 3 +-
.../rest/server/views/JobLogCard_BrowserTest.java | 11 +-
.../rest/server/views/JobLogRegion_Test.java | 6 +-
.../juneau/rest/server/views/QuickStat_Test.java | 36 +-
.../rest/server/views/QuickStats_BrowserTest.java | 56 +--
.../juneau/rest/server/views/RegionTable_Test.java | 1 -
.../rest/server/views/RelatedList_BrowserTest.java | 11 +-
.../rest/server/views/RibbonItem_Bus_Test.java | 9 +-
.../rest/server/views/RibbonItem_Parity_Test.java | 4 +-
.../juneau/rest/server/views/RibbonItem_Test.java | 67 ++--
.../server/views/RibbonItem_VisibleWhen_Test.java | 6 +-
.../juneau/rest/server/views/RunViewCss_Test.java | 5 +-
.../rest/server/views/RunViewEndpoints_Test.java | 4 +-
.../juneau/rest/server/views/RunViewLog_Test.java | 11 +-
.../rest/server/views/RunViewMixin_Test.java | 3 +
.../rest/server/views/RunView_BrowserTest.java | 11 +-
.../juneau/rest/server/views/TableSpec_Test.java | 6 +-
.../server/views/TableSpec_ToCardBody_Test.java | 41 ++-
.../rest/server/views/ViewsCssTokens_Test.java | 6 +-
.../rest/server/views/ViewsJs_ActionsRun_Test.java | 36 +-
.../server/views/ViewsJs_BusBridgeSse_Test.java | 2 +-
.../server/views/ViewsJs_BusBridgeWs_Test.java | 2 +-
.../rest/server/views/ViewsJs_BusBridge_Test.java | 2 +-
.../rest/server/views/ViewsJs_Hooks_Test.java | 8 +-
.../rest/server/views/ViewsJs_RibbonBus_Test.java | 4 +-
.../server/views/ViewsJs_RibbonNormalize_Test.java | 2 +-
.../rest/server/views/ViewsJs_TableBus_Test.java | 18 +-
.../rest/server/views/VisibilityRule_Test.java | 10 +-
.../src/test/js/actions-run.cjs | 111 +++---
.../src/test/js/badges.cjs | 26 +-
.../src/test/js/badges.html.cjs | 2 +-
.../src/test/js/bulk-selection.cjs | 37 +-
.../src/test/js/bus-bridge-sse.cjs | 161 ++++-----
.../src/test/js/bus-bridge-ws.cjs | 72 ++--
.../src/test/js/bus-bridge.cjs | 12 +-
.../src/test/js/bus-core.cjs | 40 ++-
.../src/test/js/bus-frames.cjs | 6 +-
.../src/test/js/bus-wiring.cjs | 4 +-
.../src/test/js/bus-wraps.cjs | 26 +-
.../src/test/js/card-lift.cjs | 2 +-
.../test/js/{card-lift.cjs => card-lift.cjs.bak} | 0
.../src/test/js/charts-options.cjs | 46 +--
.../src/test/js/charts.cjs | 247 +++++++-------
.../src/test/js/chrome-tip.cjs | 2 +-
.../src/test/js/client-column-search.cjs | 2 +-
.../src/test/js/column-search.cjs | 2 +-
.../src/test/js/confirm-without-dialog.cjs | 10 +-
.../src/test/js/console-bus.cjs | 50 +--
.../src/test/js/console-card-context.cjs | 34 +-
.../src/test/js/console-cards.cjs | 34 +-
.../src/test/js/console-dom-shim.cjs | 2 +-
.../src/test/js/console-shell-bus.cjs | 44 ++-
.../src/test/js/console-shell.cjs | 45 +--
.../src/test/js/console-visibility.cjs | 18 +-
.../src/test/js/csrf-boundary.cjs | 28 +-
.../src/test/js/dashboard-fuzz.cjs | 45 +--
.../src/test/js/dashboard.cjs | 106 +++---
.../src/test/js/data-registry.cjs | 4 +-
.../juneau-rest-server-views/src/test/js/data.cjs | 121 +++----
.../src/test/js/detail-region-join.cjs | 12 +-
.../src/test/js/detail-region-params.cjs | 13 +-
.../src/test/js/detail-region-visible-when.cjs | 12 +-
.../src/test/js/dialog-child-catalog.cjs | 16 +-
.../src/test/js/dialog-form.cjs | 6 +-
.../src/test/js/dialog-handle.cjs | 2 +-
.../src/test/js/edit-renderer.cjs | 14 +-
.../src/test/js/export-detect.cjs | 2 +-
.../src/test/js/export-loud.html.cjs | 2 +-
.../src/test/js/hooks-api.cjs | 4 +-
.../src/test/js/job-host.cjs | 20 +-
.../src/test/js/job-log-card.cjs | 130 +++----
.../src/test/js/job-log-region.cjs | 77 +++--
.../juneau-rest-server-views/src/test/js/jobs.cjs | 103 +++---
.../src/test/js/juneau-charts-harness.cjs | 10 +-
.../src/test/js/regions-bus-topics.cjs | 4 +-
.../src/test/js/regions-primitive.cjs | 2 +-
.../src/test/js/related-list.cjs | 6 -
.../src/test/js/ribbon-bus.cjs | 12 +-
.../src/test/js/ribbon-corpus.cjs | 6 +-
.../src/test/js/ribbon-dialog.cjs | 8 +-
.../src/test/js/ribbon-normalize.cjs | 2 +-
.../src/test/js/ribbon-parity-browser.cjs | 8 +-
.../src/test/js/row-actions-run.cjs | 8 +-
.../src/test/js/row-selection-bulk.cjs | 31 +-
.../juneau-rest-server-views/src/test/js/rules.cjs | 4 +-
.../src/test/js/run-view-browser.cjs | 14 +-
.../src/test/js/run-view-env-check.cjs | 6 +-
.../src/test/js/run-view-env.cjs | 14 +-
.../src/test/js/run-view-poll.cjs | 36 +-
.../src/test/js/run-view.cjs | 132 ++++----
.../src/test/js/same-origin-path.cjs | 20 +-
.../src/test/js/scheme-script.cjs | 13 +-
.../src/test/js/slot-mount.cjs | 2 +-
.../src/test/js/table-bus.cjs | 31 +-
.../src/test/js/urlstate-directives.cjs | 2 +-
.../src/test/js/views-dom-shim.cjs | 2 +-
.../src/test/resources/console-bus/cards.js | 3 +-
.../console-visual/nav-computed-baseline.json | 44 +--
.../org/apache/juneau/widgets/juneau-calendar.js | 4 +-
.../rest/server/widgets/CalendarEvent_Test.java | 14 +-
.../server/widgets/ModalDef_ChromeSteps_Test.java | 9 +-
.../src/test/js/juneau-calendar.cjs | 7 +-
.../apache/juneau/rest/server/RestOperations.java | 10 +-
.../juneau/rest/server/filter/BoundaryChecks.java | 5 +-
.../juneau/rest/server/filter/CsrfBoundary.java | 9 +-
.../juneau/rest/server/filter/ForwardedOrigin.java | 12 +
.../juneau/rest/server/filter/HandshakeHosts.java | 3 +
.../juneau/rest/server/filter/PeerRanges.java | 16 +-
.../rest/server/staticfile/WebJarResolver.java | 4 +-
.../juneau/rest/server/MethodSafety_Test.java | 6 +-
.../server/RestContext_PathsAndBeans_Test.java | 4 +-
.../rest/server/auth/AuthFilterChain_Test.java | 4 +-
.../rest/server/filter/CsrfBoundaryChain_Test.java | 2 +-
.../server/filter/CsrfBoundaryFilter_Test.java | 2 +-
.../server/filter/CsrfBoundaryForwarded_Test.java | 41 ++-
.../rest/server/filter/CsrfBoundary_Test.java | 27 +-
.../juneau/rest/server/filter/CsrfTokens_Test.java | 6 +-
.../rest/server/sse/SseSubscription_Test.java | 10 +-
.../rest/server/runreport/JUnitXmlParser.java | 25 +-
.../server/runreport/JestJsonReportReader.java | 53 +--
.../runreport/PlaywrightJsonReportReader.java | 10 +-
.../juneau/rest/server/runreport/ReportJson.java | 6 +
.../juneau/rest/server/runreport/ReportResult.java | 78 +----
.../juneau/rest/server/runreport/ReportText.java | 8 +-
.../juneau/rest/server/runreport/RunEvent.java | 6 +
.../runreport/JestJsonReportReader_Test.java | 2 +-
.../rest/server/runreport/ReportText_Test.java | 1 -
juneau-run/src/test/python/test_history.py | 2 +-
.../secret/macos/keychain/KeychainSecretStore.java | 102 +++++-
.../macos/keychain/KeychainSecretStore_Test.java | 76 ++++-
470 files changed, 4820 insertions(+), 3330 deletions(-)
diff --git a/juneau-bean/juneau-bean-jsonpatch/src/test/java/org/apache/juneau/bean/jsonpatch/JsonPatchMarshaller_Test.java b/juneau-bean/juneau-bean-jsonpatch/src/test/java/org/apache/juneau/bean/jsonpatch/JsonPatchMarshaller_Test.java
index ea72f7f8b8..55bf0757cb 100644
--- a/juneau-bean/juneau-bean-jsonpatch/src/test/java/org/apache/juneau/bean/jsonpatch/JsonPatchMarshaller_Test.java
+++ b/juneau-bean/juneau-bean-jsonpatch/src/test/java/org/apache/juneau/bean/jsonpatch/JsonPatchMarshaller_Test.java
@@ -113,7 +113,9 @@ class JsonPatchMarshaller_Test extends TestBase {
}
@Override
- public void close() {}
+ public void close() {
+ // no-op by design: test stub
+ }
}
private static final class FailingWriter extends Writer {
@@ -123,10 +125,14 @@ class JsonPatchMarshaller_Test extends TestBase {
}
@Override
- public void flush() {}
+ public void flush() {
+ // no-op by design: test stub
+ }
@Override
- public void close() {}
+ public void close() {
+ // no-op by design: test stub
+ }
}
@Test
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
index d41e7c9e61..5e8c1e2da6 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
@@ -1540,8 +1540,8 @@ public class BeanMeta<T> {
// Package-private seam so tests can force setAccessible() to report failure.
static ConstructorInfo makeRecordConstructorAccessible(ClassInfo ci, ConstructorInfo rcon, Predicate<ConstructorInfo> accessor) {
- // Always attempt setAccessible (a public record nested in a non-public class still needs it);
- // only fail loudly when the record is not effectively public.
+ // Always attempt to make the constructor accessible, since a public record nested in a non-public class still needs it.
+ // Only fail loudly when the record is not effectively public.
var ok = accessor.test(rcon);
if (! ok && ! (rcon.isPublic() && isEffectivelyPublic(ci))) {
var pkg = ci.getPackage() == null ? "" : ci.getPackage().getName();
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/InMemoryMatch.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/InMemoryMatch.java
index b4793ae125..5e0d718e91 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/InMemoryMatch.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/InMemoryMatch.java
@@ -137,6 +137,9 @@ final class InMemoryMatch {
return v != null && v.toLowerCase(Locale.ROOT).contains(arg.toLowerCase(Locale.ROOT));
}
+ @SuppressWarnings({
+ "javabugs:S2259" // Only caller is matchBare(), whose literal node value comes from the parser's decodeLiteral() and is never null.
+ })
private static boolean hasWildcard(String token) {
return token.indexOf('*') >= 0 || token.indexOf('?') >= 0;
}
@@ -354,7 +357,8 @@ final class InMemoryMatch {
}
@SuppressWarnings({
- "java:S1168" // Private sentinel: null means "not a version", distinct from any parsed (possibly zero-length) value; hot sort path.
+ "java:S1168", // Private sentinel: null means "not a version", distinct from any parsed (possibly zero-length) value; hot sort path.
+ "javabugs:S2259" // The ib(v) guard returns for a null or blank v before v.strip().
})
private static int[] version(String v) {
if (ib(v))
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/QueryProperty.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/QueryProperty.java
index 84817436c9..c941ab5ec4 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/QueryProperty.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/beanquery/QueryProperty.java
@@ -183,6 +183,9 @@ public final class QueryProperty {
* @throws IllegalArgumentException If <c>bean</c> is <jk>null</jk>.
* @throws IllegalStateException If the property is not writable.
*/
+ @SuppressWarnings({
+ "java:S3011" // Field.set on a public field; no accessibility override, reflection is the point of this class.
+ })
public void write(Object bean, Object value) {
reqnn("bean", bean);
if (! canWrite())
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/http/SafePathTemplate.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/http/SafePathTemplate.java
index 45be313a4f..22279087b8 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/http/SafePathTemplate.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/http/SafePathTemplate.java
@@ -71,6 +71,9 @@ public final class SafePathTemplate {
* @param path The candidate path. Can be <jk>null</jk>.
* @return <jk>true</jk> if the string is a same-origin path.
*/
+ @SuppressWarnings({
+ "java:S3776" // Flat sequence of independent rejection checks; splitting it would obscure the security rules.
+ })
public static boolean isSameOriginPath(String path) {
if (path == null || path.isBlank())
return false;
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecordCapture.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecordCapture.java
index dee862c8fd..0a1f679ba4 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecordCapture.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecordCapture.java
@@ -76,6 +76,9 @@ public class LogRecordCapture implements LogRecordListener, Closeable {
* @param body The code to run. Checked exceptions are rethrown wrapped in a {@link RuntimeException}.
* @return The captured records, in the order logged. Never <jk>null</jk>.
*/
+ @SuppressWarnings({
+ "java:S1181" // Snippet.run() throws Throwable; Errors are rethrown and checked exceptions wrapped
+ })
public static List<java.util.logging.LogRecord> quietly(String loggerName, Snippet body) {
var records = Collections.synchronizedList(new ArrayList<java.util.logging.LogRecord>());
var handler = new Handler() {
@@ -128,6 +131,9 @@ public class LogRecordCapture implements LogRecordListener, Closeable {
* @param loggerClass The class whose logger is silenced.
* @return A handle that restores the logger when closed. Never <jk>null</jk>.
*/
+ @SuppressWarnings({
+ "resource" // The returned handle is owned by the caller, who closes it.
+ })
public static Quiet quiet(Class<?> loggerClass) {
return quiet(loggerClass.getName());
}
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/beanquery/SearchOperatorSet_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/beanquery/SearchOperatorSet_Test.java
index df36c9dc17..bbd5140842 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/beanquery/SearchOperatorSet_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/beanquery/SearchOperatorSet_Test.java
@@ -130,8 +130,9 @@ class SearchOperatorSet_Test extends TestBase {
@Test
void d04_customOperatorStillRequiresHelp() {
- assertThrows(IllegalArgumentException.class, () -> SearchOperator.create("$near", " ").build());
- assertThrows(IllegalArgumentException.class, () -> SearchOperator.create("$near", "x").help(null).build());
+ assertThrows(IllegalArgumentException.class, () -> SearchOperator.create("$near", " "));
+ var noHelp = SearchOperator.create("$near", "x").help(null);
+ assertThrows(IllegalArgumentException.class, noHelp::build);
}
//====================================================================================================
diff --git a/juneau-core/juneau-config/src/test/java/org/apache/juneau/config/internal/ConfigMap_Test.java b/juneau-core/juneau-config/src/test/java/org/apache/juneau/config/internal/ConfigMap_Test.java
index f202f8c016..59db997e00 100644
--- a/juneau-core/juneau-config/src/test/java/org/apache/juneau/config/internal/ConfigMap_Test.java
+++ b/juneau-core/juneau-config/src/test/java/org/apache/juneau/config/internal/ConfigMap_Test.java
@@ -19,6 +19,7 @@ package org.apache.juneau.config.internal;
import static org.junit.jupiter.api.Assertions.*;
import java.util.*;
+import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import org.apache.juneau.config.format.*;
@@ -68,15 +69,10 @@ class ConfigMap_Test {
@Override
public synchronized String write(String name, String expectedContents, String newContents) {
update(name, stale);
- new Thread(() -> {
- try {
- Thread.sleep(300);
- } catch (@SuppressWarnings("unused") InterruptedException e) {
- Thread.currentThread().interrupt();
- }
+ CompletableFuture.runAsync(() -> {
realEventDelivered.set(true);
update(name, newContents);
- }).start();
+ }, CompletableFuture.delayedExecutor(300, TimeUnit.MILLISECONDS));
return null;
}
}
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamSerializerSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamSerializerSession.java
index 4a10a6a88c..adb4d08eab 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamSerializerSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamSerializerSession.java
@@ -356,7 +356,7 @@ public class RdfStreamSerializerSession extends OutputStreamSerializerSession {
else
n = m.createTypedLiteral(o); // HTT: unreachable — see guard above.
} else if (sType.isReader()) {
- n = m.createLiteral(encodeTextInvalidChars(read((Reader)o, SerializerSession::handleThrown))); // HTT: the catch(IOException)->accept(e) path IS genuinely exercised (RdfSerializer_Test#o11_stream_serialize_reader_ioException_wrapped; a throwing Reader triggers this and yields a SerializeException wrapping the IOException — proven by a temporary System.err probe inside the lambda body during triage, which printed on every run) — but JaCoCo persistently reports the compiler-synthesized [...]
+ n = m.createLiteral(encodeTextInvalidChars(read((Reader)o, SerializerSession::handleThrown))); // HTT: the catch(IOException)->accept(e) path IS genuinely exercised (RdfSerializer_Test#o11_stream_serialize_reader_ioException_wrapped; a throwing Reader triggers this and yields a SerializeException wrapping the IOException — proven by a temporary System.err probe inside the lambda body during triage, which printed on every run) — but JaCoCo persistently reports the compiler-synthesized [...]
} else if (sType.isInputStream()) {
n = m.createLiteral(encodeTextInvalidChars(read((InputStream)o, SerializerSession::handleThrown))); // HTT: same tooling artifact as the Reader branch above — RdfSerializer_Test#o12_stream_serialize_inputstream_ioException_wrapped exercises this (confirmed via the same temporary System.err probe technique), but JaCoCo reports the synthesized `lambda$writeAnything$1` method as 0% covered regardless. Waived as a tooling artifact, not a real gap.
} else {
diff --git a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParserSerializerSet_DefaultMediaTypes_Test.java b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParserSerializerSet_DefaultMediaTypes_Test.java
index 212ec775b2..def2924380 100644
--- a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParserSerializerSet_DefaultMediaTypes_Test.java
+++ b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParserSerializerSet_DefaultMediaTypes_Test.java
@@ -82,7 +82,7 @@ class RdfParserSerializerSet_DefaultMediaTypes_Test extends TestBase {
return f.get(null);
var create = ownCreate(c);
if (create != null) {
- var o = ((Context.Builder)create.invoke(null)).build();
+ var o = ((Context.Builder<?>)create.invoke(null)).build();
return o.getClass() == c ? o : null;
}
// A nested variant without its own create() (for example XmlDocSerializer.Ns) is built from its enclosing
diff --git a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParser_Test.java b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParser_Test.java
index 78080e5ff8..e912c77f08 100644
--- a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParser_Test.java
+++ b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfParser_Test.java
@@ -2340,8 +2340,8 @@ class RdfParser_Test extends TestBase {
}
public interface M36_EmptyInterface {
- // No bean properties at all -- canCreateNewInstance() is FALSE, so readAnything falls all
- // the way through to the final `else if (n.isResource())` generic-map branch.
+ // No bean properties at all, so the type cannot create a new instance and readAnything falls all
+ // the way through to the final resource branch that builds a generic map.
}
@Test void m36_readAnything_typeProperty_unresolvableName_genericMapCast() {
diff --git a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfSerializer_Test.java b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfSerializer_Test.java
index 583d70ea28..11aa1921e6 100644
--- a/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfSerializer_Test.java
+++ b/juneau-core/juneau-marshall-rdf/src/test/java/org/apache/juneau/marshall/jena/RdfSerializer_Test.java
@@ -1815,8 +1815,8 @@ class RdfSerializer_Test extends TestBase {
}
@Test void o11_stream_serialize_reader_ioException_wrapped() {
- // A Reader that throws mid-read — covers the catch(IOException) -> onException.accept(e) ->
- // handleThrown(e) path inside IoUtils.read(Reader, Consumer) (line 376's residual instructions,
+ // A Reader that throws mid-read: covers the IOException handler inside the reader-reading helper, which
+ // passes the failure on to the serializer session's thrown-exception handling (residual instructions
// never exercised by n05's happy-path StringReader).
var s = RdfStreamSerializer.create().language(Constants.LANG_RDFTHRIFT).build();
assertThrows(Exception.class, () -> s.write(new O11_ThrowingReader()));
@@ -1850,9 +1850,9 @@ class RdfSerializer_Test extends TestBase {
// was enabled — see SerializerSession_Test#i01_listener_beanGetterException_ignored_doesNotThrow,
// which documents this exact BeanContext-level short-circuit for JSON). With the setting left at
// its default (false), the getter's exception instead propagates out of bpm.get(...), IS caught by
- // forEachValue's catch(Exception), and IS surfaced as a non-null BeanPropertyValue.getThrown() —
- // which reaches line 407's onBeanGetterException(bpMeta, t) call, and since
- // isIgnoreInvocationExceptionsOnGetters() is false there too, it rethrows as a SerializeException.
+ // the catch block in forEachValue, and IS surfaced as a non-null BeanPropertyValue.getThrown() —
+ // which reaches line 407's bean-getter-exception callback, and since the ignore-invocation-exceptions
+ // setting is false there too, it rethrows as a SerializeException.
var s = RdfStreamSerializer.create().language(Constants.LANG_RDFTHRIFT).build();
assertThrows(Exception.class, () -> s.write(new O13_ThrowingGetterBean()));
}
@@ -1959,9 +1959,9 @@ class RdfSerializer_Test extends TestBase {
}
@Test void q06_serialize_multiValued_disableAutoDetectNamespaces_skipsAddModelPrefix() throws Exception {
- // ns != null (from the property's own @Rdf namespace) AND isAutoDetectNamespaces()==FALSE --
- // covers the FALSE side of writeToMultiProperties' own "else if (isAutoDetectNamespaces())"
- // check (distinct from writeBeanMap's identical-shaped check, already covered for the FALSE
+ // The namespace is set (from the property's own @Rdf namespace) AND auto-detect namespaces is off:
+ // covers the FALSE side of writeToMultiProperties' own auto-detect check
+ // (distinct from writeBeanMap's identical-shaped check, already covered for the FALSE
// side by m11).
var s = RdfSerializer.create().ntriple().disableAutoDetectNamespaces().build();
var result = s.write(new Q06_BeanWithMultiValuedNsProperty());
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/MissingRequiredPropertyException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/MissingRequiredPropertyException.java
index 132c9a299b..d944109666 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/MissingRequiredPropertyException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/MissingRequiredPropertyException.java
@@ -68,6 +68,9 @@ public class MissingRequiredPropertyException extends ParseException {
* @return The same bean map, for chaining.
* @throws MissingRequiredPropertyException If a required property was never written.
*/
+ @SuppressWarnings({
+ "java:S1168" // Pass-through for chaining: returns the argument itself, so null in gives null out
+ })
public static <T> BeanMap<T> check(ParserSession session, BeanMap<T> m) {
if (m == null)
return null;
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/WriteOnlyColumns_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/WriteOnlyColumns_Test.java
index 1b9abacfe3..23968daf74 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/WriteOnlyColumns_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/WriteOnlyColumns_Test.java
@@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.*;
import java.util.*;
import org.apache.juneau.commons.bean.*;
-import org.apache.juneau.marshall.*;
import org.apache.juneau.marshall.csv.*;
import org.apache.juneau.marshall.html.*;
import org.apache.juneau.marshall.cbor.*;
@@ -127,7 +126,7 @@ class WriteOnlyColumns_Test extends TestBase {
assertEquals("pw", l.get(0).secretword);
}
- @Test void b03_beanMapPutStillSetsWriteOnly() throws Exception {
+ @Test void b03_beanMapPutStillSetsWriteOnly() {
var m = org.apache.juneau.marshall.MarshallingContext.DEFAULT.newBeanMap(User.class);
m.put("secretword", "pw");
assertEquals("pw", m.getBean().secretword);
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/MissingRequiredProperty_Conversion_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/MissingRequiredProperty_Conversion_Test.java
index ad9c06b45e..6ffc32bf2e 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/MissingRequiredProperty_Conversion_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/MissingRequiredProperty_Conversion_Test.java
@@ -46,8 +46,9 @@ class MissingRequiredProperty_Conversion_Test extends TestBase {
public static class Holder { public List<A> items; }
@Test void a01_convertToType_missing() {
+ var input = JsonMap.of("age", 1);
var e = assertThrows(MissingRequiredPropertyException.class,
- () -> MarshallingContext.DEFAULT_SESSION.convertToType(JsonMap.of("age", 1), A.class));
+ () -> MarshallingContext.DEFAULT_SESSION.convertToType(input, A.class));
assertList(e.getPropertyNames(), "name");
assertFalse(e.getMessage().contains("At: "), e.getMessage()); // no parser session, so no position
}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ParserSerializerSet_DefaultMediaTypes_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ParserSerializerSet_DefaultMediaTypes_Test.java
index 55c0caaf26..e6253b7b1b 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ParserSerializerSet_DefaultMediaTypes_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ParserSerializerSet_DefaultMediaTypes_Test.java
@@ -92,7 +92,7 @@ class ParserSerializerSet_DefaultMediaTypes_Test extends TestBase {
return f.get(null);
var create = ownCreate(c);
if (create != null) {
- var o = ((Context.Builder)create.invoke(null)).build();
+ var o = ((Context.Builder<?>)create.invoke(null)).build();
return o.getClass() == c ? o : null;
}
// A nested variant without its own create() (for example XmlDocSerializer.Ns) is built from its enclosing
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/RecordComponentOrder_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/RecordComponentOrder_Test.java
index 0889e38dc3..b8fbe275a4 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/RecordComponentOrder_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/RecordComponentOrder_Test.java
@@ -106,8 +106,8 @@ class RecordComponentOrder_Test extends TestBase {
@Test void b06_csvColumnOrderFollowsBeanOrder() {
var unsorted = CsvSerializer.create().unsortedProperties().build();
- assertEquals("zeta,alpha", unsorted.write(List.of(new B2())).toString().lines().findFirst().orElse(""));
- assertEquals("alpha,zeta", CsvSerializer.DEFAULT.write(List.of(new B2())).toString().lines().findFirst().orElse(""));
+ assertEquals("zeta,alpha", unsorted.write(List.of(new B2())).lines().findFirst().orElse(""));
+ assertEquals("alpha,zeta", CsvSerializer.DEFAULT.write(List.of(new B2())).lines().findFirst().orElse(""));
}
@Test void b07_parseRoundTripUnaffected() {
@@ -117,8 +117,8 @@ class RecordComponentOrder_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // d - precedence (moved from commons BeanMeta_DeclarationOrder_Test d01: commons BeanMeta.of ignores @BeanType;
- // the d02 @BeanType(unsorted) case is covered by b04)
+ // d - precedence (moved from the commons declaration-order test: the commons bean metadata ignores the bean type annotation;
+ // the unsorted bean type case is covered by b04)
//-----------------------------------------------------------------------------------------------------------------
@BeanType(properties="mid,zeta")
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/parser/MissingRequiredProperty_Formats_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/parser/MissingRequiredProperty_Formats_Test.java
index 3071cd902a..99f3a09d1b 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/parser/MissingRequiredProperty_Formats_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/parser/MissingRequiredProperty_Formats_Test.java
@@ -110,7 +110,7 @@ class MissingRequiredProperty_Formats_Test extends TestBase {
assertThrows(MissingRequiredPropertyException.class, () -> CsvParser.DEFAULT.read(in, List.class, A.class));
}
- @Test void b02_openApi() throws Exception {
+ @Test void b02_openApi() {
assertThrows(MissingRequiredPropertyException.class, () -> OpenApiParser.DEFAULT.read("age=7", A.class));
}
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_Debug_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_Debug_Test.java
index e832943bb1..8b34ae4e5a 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_Debug_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_Debug_Test.java
@@ -49,7 +49,7 @@ class Rest_Debug_Test extends TestBase {
MockRestClient.buildJson5(A.class).get("/a").run().assertContent("false");
}
- @Test void a02_isDebugTrueWhenLoggerRaised() throws Exception {
+ @Test void a02_isDebugTrueWhenLoggerRaised() {
// debug() raises the resource-class logger to FINEST → loggable at FINE → isDebug() true.
var records = LogRecordCapture.quietly(RestClient.class, () -> {
try {
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/VirtualThreadDispatch_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/VirtualThreadDispatch_Test.java
index 7d82b0cd3e..131ab5bc92 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/VirtualThreadDispatch_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/VirtualThreadDispatch_Test.java
@@ -119,7 +119,7 @@ class VirtualThreadDispatch_Test extends TestBase {
public String ok() { return "ok"; }
}
- @Test void b01_degradation_handlerStillWorks() throws Exception {
+ @Test void b01_degradation_handlerStillWorks() {
// Whether we're on Java 17 (graceful degradation) or Java 21 (real VT), the handler must respond.
var c = MockRestClient.buildLax(B.class);
var records = LogRecordCapture.quietly(RestContext.class, () -> c.get("/ok").run().assertStatus(200).assertContent().isContains("ok"));
@@ -134,7 +134,7 @@ class VirtualThreadDispatch_Test extends TestBase {
@Test
@DisabledForJreRange(min = JAVA_21)
- void b02_java17_logsWarningOnce() throws Exception {
+ void b02_java17_logsWarningOnce() {
// Capture the WARNING emitted by RestContext when @Rest(virtualThreads=true) is configured on Java < 21.
var records = LogRecordCapture.quietly(RestContext.class, () -> MockRestClient.buildLax(BWarning.class).get("/x").run().assertStatus(200));
assertEquals(1, records.size(), records::toString);
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_GuardIntegration_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_GuardIntegration_Test.java
index a420d77ba0..07ff5b813e 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_GuardIntegration_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_GuardIntegration_Test.java
@@ -155,7 +155,7 @@ class AuthFilterChain_GuardIntegration_Test extends TestBase {
assertFalse(w.isUserInRole("user"));
}
- @Test void a03_bothCredentials_bearerPrincipalWins_rolesNotUnionedAcrossDistinctPrincipals() throws Exception {
+ @Test void a03_bothCredentials_bearerPrincipalWins_rolesNotUnionedAcrossDistinctPrincipals() {
// Both bearer-user (alice, user role) and apikey-admin (bob, admin role) present.
// Bearer is registered first → alice wins for principal; bob is a DIFFERENT principal, so his
// admin role must NOT be unioned onto alice's identity.
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_Test.java
index 22fbbe3754..60802f881c 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/auth/AuthFilterChain_Test.java
@@ -154,7 +154,7 @@ class AuthFilterChain_Test extends TestBase {
assertInstanceOf(AuthenticatedRequestWrapper.class, capturing.captured);
}
- @Test void a04_firstSuccessPrincipalWins() throws Exception {
+ @Test void a04_firstSuccessPrincipalWins() {
var chain = AuthFilterChain.create(null)
.append(succeeds(ALICE, "user"))
.append(succeeds(BOB, "admin"))
@@ -167,7 +167,7 @@ class AuthFilterChain_Test extends TestBase {
assertSame(ALICE, w.getUserPrincipal());
}
- @Test void a05_roleAggregation_unionAcrossSuccessfulFilters() throws Exception {
+ @Test void a05_roleAggregation_unionAcrossSuccessfulFilters() {
var chain = AuthFilterChain.create(null)
.append(succeeds(ALICE, "user"))
.append(succeeds(BOB, "admin", "billing"))
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/servlet/RestServlet_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/servlet/RestServlet_Test.java
index 38fe30fc2f..1168ab39eb 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/servlet/RestServlet_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/servlet/RestServlet_Test.java
@@ -348,11 +348,7 @@ class RestServlet_Test extends TestBase {
@Test void h01_serviceCatchesAndSendsError() throws Exception {
// A servlet that was never initialized has no context, so service() fails before dispatching and must catch
// the exception and call resp.sendError(500, ...).
- var s = new A();
- var req = mock(HttpServletRequest.class);
- var resp = mock(HttpServletResponse.class);
- s.service(req, resp);
- verify(resp).sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), anyString());
+ c01_serviceWhenContextNullSendsError();
}
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxy_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxy_Test.java
index 60a4386ce7..4a5eb98776 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxy_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxy_Test.java
@@ -50,7 +50,6 @@ import org.apache.juneau.marshall.urlencoding.*;
import org.apache.juneau.marshall.xml.*;
import org.apache.juneau.rest.mock.classic.*;
import org.apache.juneau.testutils.pojos.*;
-import org.junit.jupiter.api.*;
import org.junit.jupiter.params.*;
import org.junit.jupiter.params.provider.*;
import org.opentest4j.*;
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/validation/RestValidation_MissingProvider_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/validation/RestValidation_MissingProvider_Test.java
index 4f426e8158..92afdf26ad 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/validation/RestValidation_MissingProvider_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/validation/RestValidation_MissingProvider_Test.java
@@ -70,7 +70,7 @@ class RestValidation_MissingProvider_Test extends TestBase {
}
@Test
- void a01_missingProvider_violatingPayload_isPassedThrough() throws Exception {
+ void a01_missingProvider_violatingPayload_isPassedThrough() {
BeanValidator.simulateProviderMissingForTesting();
var a = MockRestClient.buildLax(A.class);
// Even though @Valid is present and the bean has a @NotBlank-violating field, with the provider
@@ -90,7 +90,7 @@ class RestValidation_MissingProvider_Test extends TestBase {
}
@Test
- void a02_missingProvider_validPayload_alsoPassesThrough() throws Exception {
+ void a02_missingProvider_validPayload_alsoPassesThrough() {
BeanValidator.simulateProviderMissingForTesting();
var a = MockRestClient.buildLax(A.class);
// Sanity check — the missing-provider path also lets valid payloads through. We're verifying the
diff --git a/juneau-microservice/juneau-microservice-examples/src/main/java/org/apache/juneau/microservice/examples/AdminBoundary.java b/juneau-microservice/juneau-microservice-examples/src/main/java/org/apache/juneau/microservice/examples/AdminBoundary.java
index 51aec30693..24a6dbda51 100644
--- a/juneau-microservice/juneau-microservice-examples/src/main/java/org/apache/juneau/microservice/examples/AdminBoundary.java
+++ b/juneau-microservice/juneau-microservice-examples/src/main/java/org/apache/juneau/microservice/examples/AdminBoundary.java
@@ -93,7 +93,7 @@ public final class AdminBoundary {
private static final String[] PATHS = { "/config", "/logs", "/shutdown" };
// One or more "/segment" parts of unreserved characters, so every pattern built on it is one the container matches.
- private static final Pattern PREFIX = Pattern.compile("(/[A-Za-z0-9_~-][A-Za-z0-9._~-]*)*");
+ private static final Pattern PREFIX = Pattern.compile("(?:/[A-Za-z0-9_~-][A-Za-z0-9._~-]*+)*+");
private AdminBoundary() {}
diff --git a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/AdminBoundary_Test.java b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/AdminBoundary_Test.java
index 134debd58d..0c1d56402e 100644
--- a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/AdminBoundary_Test.java
+++ b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/AdminBoundary_Test.java
@@ -36,6 +36,9 @@ import jakarta.servlet.http.*;
* The decision tests drive the filter itself with mock servlet objects and a counting chain. A mock REST client would
* not do: it never runs a servlet filter, so a test built on it passes with no boundary installed.
*/
+@SuppressWarnings({
+ "java:S3415" // Expected value is already first; Sonar misreads the upper-case LOOPBACK_HOSTS constant as the expected argument
+})
class AdminBoundary_Test extends TestBase {
private static final String HOST = "localhost:10000";
diff --git a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DebugResource_Test.java b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DebugResource_Test.java
index c2cefb65c7..60a52f8c04 100644
--- a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DebugResource_Test.java
+++ b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DebugResource_Test.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.*;
*/
class DebugResource_Test extends TestBase {
+ @SuppressWarnings("resource") // MockRestClient and its request/response are in-memory test doubles that hold no OS resource.
@Test void a01_threadDumpNavlink_plainGet() throws Exception {
var body = MockRestClient.create(DebugResource.class).ignoreErrors().build()
.get("/").accept("text/html").run()
diff --git a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
index 8c6b2e4bfa..a80ad60f68 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
@@ -470,8 +470,8 @@ public class JettyServerComponent implements MicroserviceListener {
public JettyServerComponent addFilter(ServletFilterRegistration registration) {
if (registration == null)
throw iaex("registration must not be null.");
- var server = getServer();
- if (server.isRunning() || server.isStopping())
+ var jetty = getServer();
+ if (jetty.isRunning() || jetty.isStopping())
throw isex("Filters must be added before the server starts.");
var filter = registration.getFilter();
var name = registration.getName().orElseGet(() -> cn(filter) + "#" + UUID.randomUUID());
@@ -495,7 +495,7 @@ public class JettyServerComponent implements MicroserviceListener {
*
* @param filter The filter instance. Cannot be <jk>null</jk>.
* @param dispatcherTypes The dispatcher types. Cannot be empty.
- * @param urlPatterns The URL patterns. At least one is required; see {@link ServletFilterRegistration.Builder#urlPatterns(String...)}.
+ * @param urlPatterns The URL patterns. At least one is required; see {@link org.apache.juneau.microservice.ServletFilterRegistration.Builder#urlPatterns(String...)}.
* @return This object.
* @throws IllegalArgumentException If an argument is invalid.
* @throws IllegalStateException If the server has already started.
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/AllowHeader_Jetty_Test.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/AllowHeader_Jetty_Test.java
index c7bd6390f1..d868f0db67 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/AllowHeader_Jetty_Test.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/AllowHeader_Jetty_Test.java
@@ -63,6 +63,7 @@ class AllowHeader_Jetty_Test extends TestBase {
private static URI base;
private static final HttpClient CLIENT = HttpClient.newHttpClient();
+ @SuppressWarnings("resource") // The connector is added to the server, which closes it in stop().
@BeforeAll
static void start() throws Exception {
server = new Server();
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocketCsrf_JettyIT.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocketCsrf_JettyIT.java
index eafcd9c0f8..1546f36132 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocketCsrf_JettyIT.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocketCsrf_JettyIT.java
@@ -19,7 +19,6 @@ package org.apache.juneau.microservice.jetty;
import static org.junit.jupiter.api.Assertions.*;
import java.io.*;
-import java.lang.reflect.*;
import java.net.*;
import java.net.http.*;
import java.nio.charset.*;
@@ -61,6 +60,9 @@ import jakarta.websocket.server.*;
*/
@EnabledIfSystemProperty(named=BusWebSocketCsrf_JettyIT.GATE, matches="true",
disabledReason="binds a socket; run with -Dtest='BusWebSocketCsrf_JettyIT' -Djuneau.busIt=true")
+@SuppressWarnings({
+ "resource" // Servers, connectors and buses are fixtures started in @BeforeAll and stopped in @AfterAll or returned to the caller that stops them; the JDK client is not a resource.
+})
class BusWebSocketCsrf_JettyIT extends TestBase {
static final String GATE = "juneau.busIt";
@@ -83,7 +85,7 @@ class BusWebSocketCsrf_JettyIT extends TestBase {
/** Accepts and does nothing; the probe configurator is what matters. */
public static class ProbeEndpoint extends Endpoint {
- @Override public void onOpen(jakarta.websocket.Session session, EndpointConfig config) {}
+ @Override public void onOpen(jakarta.websocket.Session session, EndpointConfig config) { /* no-op by design */ }
}
/** Records the handshake's request URI as the container reports it, and which of the RFC 6455 headers it carried. */
@@ -387,11 +389,10 @@ class BusWebSocketCsrf_JettyIT extends TestBase {
CsrfBoundary_JettyIT.literal(h, extra[i], extra[i + 1]);
out.write(CsrfBoundary_JettyIT.frame(0x1, 0x4, 1, h.toByteArray())); // HEADERS: END_HEADERS only, so the stream stays open
- try (var socket = new Socket("127.0.0.1", port)) {
+ try (var socket = new Socket("127.0.0.1", port); var in = new DataInputStream(socket.getInputStream())) {
socket.setSoTimeout(10_000);
socket.getOutputStream().write(out.toByteArray());
socket.getOutputStream().flush();
- var in = new DataInputStream(socket.getInputStream());
var decoder = new HpackDecoder(8192, () -> 0L);
var connectProtocol = false;
var status = -1;
@@ -427,7 +428,9 @@ class BusWebSocketCsrf_JettyIT extends TestBase {
case 0x3, 0x7 -> {
return new Ext(connectProtocol, status, null, true);
}
- default -> {}
+ default -> {
+ // other opcodes are ignored
+ }
}
}
}
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocket_JettyIT.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocket_JettyIT.java
index 084cb38ed3..cec99a7c24 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocket_JettyIT.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/BusWebSocket_JettyIT.java
@@ -45,6 +45,9 @@ import org.junit.jupiter.api.condition.*;
*/
@EnabledIfSystemProperty(named=BusWebSocket_JettyIT.GATE, matches="true",
disabledReason="binds a socket; run with -Dtest='BusWebSocket_JettyIT' -Djuneau.busIt=true")
+@SuppressWarnings({
+ "resource" // The server, bus and connector are fixtures started in @BeforeAll and stopped in @AfterAll, and the fluent HttpClient/socket chains return no resource the test owns.
+})
class BusWebSocket_JettyIT extends TestBase {
static final String GATE = "juneau.busIt";
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundaryForwarded_JettyIT.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundaryForwarded_JettyIT.java
index bde6bd2ea0..cd7d337300 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundaryForwarded_JettyIT.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundaryForwarded_JettyIT.java
@@ -57,6 +57,9 @@ import jakarta.servlet.http.*;
*/
@EnabledIfSystemProperty(named=CsrfBoundary_JettyIT.GATE, matches="true",
disabledReason="binds a socket; run with -Dtest='CsrfBoundaryForwarded_JettyIT' -Djuneau.busIt=true")
+@SuppressWarnings({
+ "resource" // The server, connector and bus are started per test and stopped in @AfterEach; servlet response writers belong to the container.
+})
class CsrfBoundaryForwarded_JettyIT extends TestBase {
private static final String PUBLIC = "https://app.example";
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundary_JettyIT.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundary_JettyIT.java
index 554e34e26e..097b114529 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundary_JettyIT.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/CsrfBoundary_JettyIT.java
@@ -56,6 +56,9 @@ import jakarta.servlet.http.*;
*/
@EnabledIfSystemProperty(named=CsrfBoundary_JettyIT.GATE, matches="true",
disabledReason="binds a socket; run with -Dtest='CsrfBoundary_JettyIT' -Djuneau.busIt=true")
+@SuppressWarnings({
+ "resource" // Servers, connectors and buses are fixtures started in @BeforeAll and stopped in @AfterAll; raw-socket chains and servlet writers are closed by the socket or owned by the container.
+})
class CsrfBoundary_JettyIT extends TestBase {
static final String GATE = "juneau.busIt";
@@ -89,32 +92,32 @@ class CsrfBoundary_JettyIT extends TestBase {
/** A {@link CsrfBoundary} that also records the dispatcher type of every request it judges. */
static final class RecordingBoundary extends CsrfBoundary {
- private final Record record;
+ private final Record rec;
- RecordingBoundary(CsrfBoundary.Builder b, Record record) {
+ RecordingBoundary(CsrfBoundary.Builder b, Record rec) {
super(b);
- this.record = record;
+ this.rec = rec;
}
@Override /* CsrfBoundary */
public BoundaryResult check(HttpServletRequest req) {
- record.judged(req);
+ rec.judged(req);
return super.check(req);
}
}
/** A {@link LoopbackBoundary} that records what the container reports about every request it judges. */
static final class RecordingLoopback extends LoopbackBoundary {
- private final Record record;
+ private final Record rec;
- RecordingLoopback(LoopbackBoundary.Builder b, Record record) {
+ RecordingLoopback(LoopbackBoundary.Builder b, Record rec) {
super(b);
- this.record = record;
+ this.rec = rec;
}
@Override /* LoopbackBoundary */
public BoundaryResult check(HttpServletRequest req) {
- record.judged(req);
+ rec.judged(req);
return super.check(req);
}
}
@@ -131,10 +134,10 @@ class CsrfBoundary_JettyIT extends TestBase {
/** A state-changing resource that counts the requests reaching it. */
static final class WriteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- private final transient Record record;
- WriteServlet(Record record) { this.record = record; }
+ private final transient Record rec;
+ WriteServlet(Record rec) { this.rec = rec; }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
- record.writes.incrementAndGet();
+ rec.writes.incrementAndGet();
res.setContentType("text/plain");
res.getWriter().write("written");
}
@@ -160,10 +163,10 @@ class CsrfBoundary_JettyIT extends TestBase {
/** A write that passes the boundary and then fails, so the container dispatches to its error page. */
static final class FailingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- private final transient Record record;
- FailingServlet(Record record) { this.record = record; }
+ private final transient Record rec;
+ FailingServlet(Record rec) { this.rec = rec; }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
- record.writes.incrementAndGet();
+ rec.writes.incrementAndGet();
res.sendError(500);
}
}
@@ -179,7 +182,7 @@ class CsrfBoundary_JettyIT extends TestBase {
}
/** A running server and the base URL it answers on. */
- record App(Server server, String base, int port, Record record) {
+ record App(Server server, String base, int port, Record rec) {
String origin() { return base; }
}
@@ -204,16 +207,16 @@ class CsrfBoundary_JettyIT extends TestBase {
}
private App start(boolean forwarded, boolean h2c, CsrfBoundary.Builder boundary, String filterPath, EnumSet<DispatcherType> types) throws Exception {
- return start(forwarded, h2c, (port, record) -> new RecordingBoundary(boundary, record), filterPath, types);
+ return start(forwarded, h2c, (port, rec) -> new RecordingBoundary(boundary, rec), filterPath, types);
}
/** Builds the boundary once the connector has its port, so a pinned authority can name it. */
private interface BoundaryFactory {
- RequestBoundary create(int port, Record record);
+ RequestBoundary create(int port, Record rec);
}
private App start(boolean forwarded, boolean h2c, BoundaryFactory boundary, String filterPath, EnumSet<DispatcherType> types) throws Exception {
- var record = new Record();
+ var rec = new Record();
var server = new Server();
var config = new HttpConfiguration();
if (forwarded)
@@ -227,12 +230,12 @@ class CsrfBoundary_JettyIT extends TestBase {
var ctx = new ServletContextHandler(ServletContextHandler.SESSIONS);
ctx.setContextPath("/");
- ctx.addFilter(new FilterHolder(new RequestBoundaryFilter(boundary.create(connector.getLocalPort(), record))), filterPath, types);
+ ctx.addFilter(new FilterHolder(new RequestBoundaryFilter(boundary.create(connector.getLocalPort(), rec))), filterPath, types);
ctx.addServlet(new ServletHolder(new TokenServlet()), "/token");
- ctx.addServlet(new ServletHolder(new WriteServlet(record)), "/write");
+ ctx.addServlet(new ServletHolder(new WriteServlet(rec)), "/write");
ctx.addServlet(new ServletHolder(new ForwardServlet()), "/fwd");
ctx.addServlet(new ServletHolder(new ViewServlet()), "/view/*");
- ctx.addServlet(new ServletHolder(new FailingServlet(record)), "/boom");
+ ctx.addServlet(new ServletHolder(new FailingServlet(rec)), "/boom");
ctx.addServlet(new ServletHolder(new ErrorServlet()), "/error");
var errors = new ErrorPageErrorHandler();
errors.addErrorPage(500, "/error");
@@ -240,7 +243,7 @@ class CsrfBoundary_JettyIT extends TestBase {
server.setHandler(ctx);
server.start();
var port = connector.getLocalPort();
- app = new App(server, "http://127.0.0.1:" + port, port, record);
+ app = new App(server, "http://127.0.0.1:" + port, port, rec);
return app;
}
@@ -290,14 +293,14 @@ class CsrfBoundary_JettyIT extends TestBase {
var ok = send(a, "POST", "/write", "X-Forwarded-Proto", "https", "X-Forwarded-Host", "app.example",
"Origin", "https://app.example", "Content-Type", JSON, LoopbackBoundary.DEFAULT_CSRF_HEADER, tok);
assertEquals(200, ok.statusCode(), ok::body);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
// The same write with no forwarded headers is judged against the socket's own origin, and refused.
var direct = send(a, "POST", "/write", "Origin", "https://app.example", "Content-Type", JSON,
LoopbackBoundary.DEFAULT_CSRF_HEADER, tok);
assertEquals(403, direct.statusCode(), direct::body);
assertEquals("ORIGIN_MISMATCH", rejection(direct));
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
@Test void a02_forwardedHeadersIgnoredWhenNoCustomizerUnderHostHeader() throws Exception {
@@ -316,13 +319,13 @@ class CsrfBoundary_JettyIT extends TestBase {
"Origin", "http://evil.example", "Content-Type", JSON, csrf, tok);
assertEquals(403, host.statusCode(), host::body);
assertEquals("ORIGIN_MISMATCH", rejection(host));
- assertEquals(0, a.record().writes.get());
+ assertEquals(0, a.rec().writes.get());
// The real origin still passes with the same headers present.
var ok = send(a, "POST", "/write", "X-Forwarded-Proto", "https", "X-Forwarded-Host", "evil.example",
"Origin", a.origin(), "Content-Type", JSON, csrf, tok);
assertEquals(200, ok.statusCode(), ok::body);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
/**
@@ -345,24 +348,24 @@ class CsrfBoundary_JettyIT extends TestBase {
@Test void a03_http2AuthorityStandsInForHost() throws Exception {
var a = start(false, true, perProcess(), "/*", REQUEST);
var tok = token(a);
- a.record().servers.clear();
- a.record().hosts.clear();
- a.record().protocols.clear();
+ a.rec().servers.clear();
+ a.rec().hosts.clear();
+ a.rec().protocols.clear();
// Characterization: the container reports :authority only as the server name and port. It surfaces no Host
// header and reports the protocol as HTTP/2.0. The boundary judges :authority in Host's place.
var res = h2cPost(a, "app.example", "http://app.example", tok);
assertEquals(200, res.status(), res::headers);
- assertEquals(List.of("app.example:80"), a.record().servers);
- assertEquals(List.of(List.of()), a.record().hosts);
- assertEquals(List.of("HTTP/2.0"), a.record().protocols);
- assertEquals(1, a.record().writes.get());
+ assertEquals(List.of("app.example:80"), a.rec().servers);
+ assertEquals(List.of(List.of()), a.rec().hosts);
+ assertEquals(List.of("HTTP/2.0"), a.rec().protocols);
+ assertEquals(1, a.rec().writes.get());
// A page of another site is still refused: Origin must be the :authority's own origin.
var foreign = h2cPost(a, "app.example", "http://evil.example", tok);
assertEquals(403, foreign.status(), foreign::headers);
assertEquals("ORIGIN_MISMATCH", foreign.rejection());
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
@Test void a04_http2AuthorityJudgedAgainstAllowedHosts() throws Exception {
@@ -371,20 +374,20 @@ class CsrfBoundary_JettyIT extends TestBase {
var ok = h2cPost(a, "app.example", "http://app.example", tok);
assertEquals(200, ok.status(), ok::headers);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
var rebound = h2cPost(a, "evil.example", "http://evil.example", tok);
assertEquals(421, rebound.status(), rebound::headers);
assertEquals("HOST_NOT_ALLOWED", rebound.rejection());
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
@Test void a05_http2WithNoAuthorityTakesTheSocketsOwnAddress() throws Exception {
var a = start(false, true, perProcess(), "/*", REQUEST);
var tok = token(a);
- a.record().servers.clear();
- a.record().hosts.clear();
- a.record().protocols.clear();
+ a.rec().servers.clear();
+ a.rec().hosts.clear();
+ a.rec().protocols.clear();
// Characterization: with no :authority the container reports its own bound address as the server name, still
// with no Host header. The boundary therefore judges the server against itself, which no browser can provoke
@@ -392,22 +395,22 @@ class CsrfBoundary_JettyIT extends TestBase {
var foreign = h2cPost(a, null, null, "http://app.example", tok);
assertEquals(403, foreign.status(), foreign::headers);
assertEquals("ORIGIN_MISMATCH", foreign.rejection());
- assertEquals(List.of("127.0.0.1:" + a.port()), a.record().servers);
- assertEquals(List.of(List.of()), a.record().hosts);
- assertEquals(List.of("HTTP/2.0"), a.record().protocols);
- assertEquals(0, a.record().writes.get());
+ assertEquals(List.of("127.0.0.1:" + a.port()), a.rec().servers);
+ assertEquals(List.of(List.of()), a.rec().hosts);
+ assertEquals(List.of("HTTP/2.0"), a.rec().protocols);
+ assertEquals(0, a.rec().writes.get());
var own = h2cPost(a, null, null, a.origin(), tok);
assertEquals(200, own.status(), own::headers);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
@Test void a06_http11RequestClaimingHttp2IsNotTrusted() throws Exception {
var a = start(false, true, perProcess(), "/*", REQUEST);
var tok = token(a);
- a.record().servers.clear();
- a.record().hosts.clear();
- a.record().protocols.clear();
+ a.rec().servers.clear();
+ a.rec().hosts.clear();
+ a.rec().protocols.clear();
// Spoof lock: the synthesis is guarded on getProtocol() being exactly HTTP/2.0, so it matters that an HTTP/1.1
// socket cannot claim that. Jetty refuses the request line itself (426), before any filter runs, so the
@@ -415,41 +418,41 @@ class CsrfBoundary_JettyIT extends TestBase {
var head = rawHttp(a, "POST /write HTTP/2.0\r\nOrigin: " + a.origin() + "\r\nContent-Type: " + JSON
+ "\r\n" + LoopbackBoundary.DEFAULT_CSRF_HEADER + ": " + tok + "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
assertTrue(head.startsWith("HTTP/1.1 426 "), head);
- assertEquals(List.of(), a.record().servers);
- assertEquals(0, a.record().writes.get());
+ assertEquals(List.of(), a.rec().servers);
+ assertEquals(0, a.rec().writes.get());
// An ordinary HTTP/1.1 request with no Host is refused by the container too (400), so the boundary's own
// HOST_MISSING never needs the protocol guard for it.
var noHost = rawHttp(a, "POST /write HTTP/1.1\r\nOrigin: " + a.origin() + "\r\nContent-Type: " + JSON
+ "\r\n" + LoopbackBoundary.DEFAULT_CSRF_HEADER + ": " + tok + "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
assertTrue(noHost.startsWith("HTTP/1.1 400 "), noHost);
- assertEquals(0, a.record().writes.get());
+ assertEquals(0, a.rec().writes.get());
}
@Test void a07_loopbackBoundaryOverHttp2() throws Exception {
var csrf = SynchronizerToken.generate();
- var a = start(false, true, (port, record) -> new RecordingLoopback(
- LoopbackBoundary.create().authority("127.0.0.1", port).token(csrf), record), "/*", REQUEST);
- a.record().servers.clear();
+ var a = start(false, true, (port, rec) -> new RecordingLoopback(
+ LoopbackBoundary.create().authority("127.0.0.1", port).token(csrf), rec), "/*", REQUEST);
+ a.rec().servers.clear();
var ok = h2cPost(a, "127.0.0.1:" + a.port(), null, "http://127.0.0.1:" + a.port(), csrf.value());
assertEquals(200, ok.status(), ok::headers);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
var foreign = h2cPost(a, "evil.example:" + a.port(), null, "http://evil.example:" + a.port(), csrf.value());
assertEquals(421, foreign.status(), foreign::headers);
assertEquals("HOST_MISMATCH", foreign.rejection());
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
// With no :authority the container names its own bound address, which is this boundary's authority. A browser
// never sends such a request; the residual is a non-browser client that already holds the token.
var none = h2cPost(a, null, null, "http://127.0.0.1:" + a.port(), csrf.value());
assertEquals(200, none.status(), none::headers);
- assertEquals(2, a.record().writes.get());
+ assertEquals(2, a.rec().writes.get());
var wrongPort = h2cPost(a, "127.0.0.1:" + (a.port() == 65535 ? 1 : a.port() + 1), null, "http://127.0.0.1:" + a.port(), csrf.value());
assertEquals(421, wrongPort.status(), wrongPort::headers);
- assertEquals(2, a.record().writes.get());
+ assertEquals(2, a.rec().writes.get());
}
/** The status and headers of an HTTP/2 response. */
@@ -482,11 +485,10 @@ class CsrfBoundary_JettyIT extends TestBase {
literal(h, "content-length", "0");
out.write(frame(0x1, 0x5, 1, h.toByteArray())); // HEADERS: END_STREAM | END_HEADERS, stream 1
- try (var socket = new Socket("127.0.0.1", a.port())) {
+ try (var socket = new Socket("127.0.0.1", a.port()); var in = new DataInputStream(socket.getInputStream())) {
socket.setSoTimeout(10_000);
socket.getOutputStream().write(out.toByteArray());
socket.getOutputStream().flush();
- var in = new DataInputStream(socket.getInputStream());
var decoder = new HpackDecoder(8192, () -> 0L);
for (;;) {
var head = new byte[9];
@@ -554,13 +556,13 @@ class CsrfBoundary_JettyIT extends TestBase {
@Test void a04_errorDispatchNotRechecked() throws Exception {
var a = start(false, perProcess(), "/*", REQUEST);
var tok = token(a);
- a.record().checked.clear();
+ a.rec().checked.clear();
var res = send(a, "POST", "/boom", "Origin", a.origin(), "Content-Type", JSON, LoopbackBoundary.DEFAULT_CSRF_HEADER, tok);
assertEquals(500, res.statusCode(), res::body);
assertEquals("the error page", res.body());
assertNull(rejection(res));
- assertEquals(1, a.record().writes.get());
- assertEquals(List.of(DispatcherType.REQUEST), a.record().checked);
+ assertEquals(1, a.rec().writes.get());
+ assertEquals(List.of(DispatcherType.REQUEST), a.rec().checked);
}
@Test void a04b_forwardDispatchToHtmlViewDoesNotMintOrBreak() throws Exception {
@@ -572,7 +574,7 @@ class CsrfBoundary_JettyIT extends TestBase {
assertEquals(200, res.statusCode(), res::body);
assertEquals("<p>view session=false</p>", res.body());
assertNull(sessionCookie(res));
- assertEquals(List.of(), a.record().checked);
+ assertEquals(List.of(), a.rec().checked);
stopApp();
var b = start(false, CsrfBoundary.create(), "/view/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD));
@@ -580,17 +582,17 @@ class CsrfBoundary_JettyIT extends TestBase {
assertEquals(200, res2.statusCode(), res2::body);
assertEquals("<p>view session=true</p>", res2.body());
assertNotNull(sessionCookie(res2), () -> res2.headers().map().toString());
- assertEquals(List.of(DispatcherType.FORWARD), b.record().checked);
+ assertEquals(List.of(DispatcherType.FORWARD), b.rec().checked);
}
@Test void a04c_errorDispatchRegisteredIsChecked() throws Exception {
var a = start(false, perProcess(), "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
var tok = token(a);
- a.record().checked.clear();
+ a.rec().checked.clear();
var res = send(a, "POST", "/boom", "Origin", a.origin(), "Content-Type", JSON, LoopbackBoundary.DEFAULT_CSRF_HEADER, tok);
assertEquals(500, res.statusCode(), res::body);
assertEquals("the error page", res.body());
- assertEquals(List.of(DispatcherType.REQUEST, DispatcherType.ERROR), a.record().checked);
+ assertEquals(List.of(DispatcherType.REQUEST, DispatcherType.ERROR), a.rec().checked);
}
//-----------------------------------------------------------------------------------------------------------------
@@ -611,7 +613,7 @@ class CsrfBoundary_JettyIT extends TestBase {
var ok = send(a, "POST", "/write", "Cookie", cookie, "Origin", a.origin(), "Content-Type", JSON, csrf, tok);
assertEquals(200, ok.statusCode(), ok::body);
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
// The token belongs to that session: without the cookie, or with another session's, it is refused.
var noSession = send(a, "POST", "/write", "Origin", a.origin(), "Content-Type", JSON, csrf, tok);
@@ -624,6 +626,6 @@ class CsrfBoundary_JettyIT extends TestBase {
var wrong = send(a, "POST", "/write", "Cookie", other, "Origin", a.origin(), "Content-Type", JSON, csrf, tok);
assertEquals(403, wrong.statusCode(), wrong::body);
assertEquals("CSRF_TOKEN_MISMATCH", rejection(wrong));
- assertEquals(1, a.record().writes.get());
+ assertEquals(1, a.rec().writes.get());
}
}
diff --git a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/ServletFilterRegistration_JettyMount_Test.java b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/ServletFilterRegistration_JettyMount_Test.java
index 20c8123e60..02eeda80b7 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/ServletFilterRegistration_JettyMount_Test.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/test/java/org/apache/juneau/microservice/jetty/ServletFilterRegistration_JettyMount_Test.java
@@ -46,6 +46,7 @@ import jakarta.servlet.http.*;
@org.apache.juneau.testing.JettyMicroserviceTest
@SuppressWarnings({
"java:S1192", // Repeated URL pattern and tag literals keep each test self-contained and readable.
+ "java:S3415", // Expected value is already first; Sonar misreads the upper-case LOG constant as the expected argument
"resource" // Microservice/Server instances are test fixtures managed by the test lifecycle; explicit close is not needed for these assertions.
})
class ServletFilterRegistration_JettyMount_Test extends TestBase {
@@ -519,8 +520,11 @@ class ServletFilterRegistration_JettyMount_Test extends TestBase {
try {
ms.start();
var c = ms.getBeanStore().getBean(JettyServerComponent.class).orElseThrow();
- assertThrows(IllegalStateException.class, () -> c.addFilter(new Recorder("L"), EnumSet.of(DispatcherType.REQUEST), "/hello/*"));
- assertThrows(IllegalStateException.class, () -> c.addFilter(ServletFilterRegistration.create(new Recorder("L")).urlPatterns("/hello/*").build()));
+ var late = new Recorder("L");
+ var req = EnumSet.of(DispatcherType.REQUEST);
+ var registration = ServletFilterRegistration.create(late).urlPatterns("/hello/*").build();
+ assertThrows(IllegalStateException.class, () -> c.addFilter(late, req, "/hello/*"));
+ assertThrows(IllegalStateException.class, () -> c.addFilter(registration));
} finally {
ms.stop();
}
@@ -536,7 +540,8 @@ class ServletFilterRegistration_JettyMount_Test extends TestBase {
assertThrows(IllegalArgumentException.class, () -> c.addFilter(null, req, "/a/*"));
assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, req));
assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, req, "/console*"));
- assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, EnumSet.noneOf(DispatcherType.class), "/a/*"));
+ var none = EnumSet.noneOf(DispatcherType.class);
+ assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, none, "/a/*"));
assertThrows(IllegalArgumentException.class, () -> c.addFilter((ServletFilterRegistration)null));
} finally {
ms.stop();
diff --git a/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java b/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
index e4a951ba27..0322e22dce 100644
--- a/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
+++ b/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
@@ -514,7 +514,7 @@ public class TomcatServerComponent implements MicroserviceListener {
*
* @param filter The filter instance. Cannot be <jk>null</jk>.
* @param dispatcherTypes The dispatcher types. Cannot be empty.
- * @param urlPatterns The URL patterns. At least one is required; see {@link ServletFilterRegistration.Builder#urlPatterns(String...)}.
+ * @param urlPatterns The URL patterns. At least one is required; see {@link org.apache.juneau.microservice.ServletFilterRegistration.Builder#urlPatterns(String...)}.
* @return This object.
* @throws IllegalArgumentException If an argument is invalid.
* @throws IllegalStateException If the server has already started.
diff --git a/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/BusWebSocketCsrf_TomcatIT.java b/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/BusWebSocketCsrf_TomcatIT.java
index 6da97e5142..d1be7e192f 100644
--- a/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/BusWebSocketCsrf_TomcatIT.java
+++ b/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/BusWebSocketCsrf_TomcatIT.java
@@ -85,6 +85,9 @@ import jakarta.websocket.server.*;
*/
@EnabledIfSystemProperty(named=BusWebSocketCsrf_TomcatIT.GATE, matches="true",
disabledReason="binds a socket; run with -Dtest='BusWebSocketCsrf_TomcatIT' -Djuneau.busIt=true")
+@SuppressWarnings({
+ "resource" // The Tomcat servers and buses are static fixtures started in @BeforeAll and stopped in @AfterAll; raw-socket chains are closed with the socket.
+})
class BusWebSocketCsrf_TomcatIT extends TestBase {
static final String GATE = "juneau.busIt";
@@ -120,7 +123,7 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
/** Accepts and does nothing; the probe configurator is what matters. */
public static class ProbeEndpoint extends Endpoint {
- @Override public void onOpen(jakarta.websocket.Session session, EndpointConfig config) {}
+ @Override public void onOpen(jakarta.websocket.Session session, EndpointConfig config) { /* no-op by design */ }
}
/** Records the handshake's request URI as the container reports it. */
@@ -161,13 +164,13 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
}
Context ctx = tomcat.addContext("", base.toString());
// The WebSocket filter only runs for a request that maps to a servlet.
- Tomcat.addServlet(ctx, "default", new HttpServlet() {
+ var dflt = Tomcat.addServlet(ctx, "default", new HttpServlet() {
private static final long serialVersionUID = 1L;
});
- ctx.addServletMappingDecoded("/", "default");
+ dflt.addMapping("/");
var wrapper = Tomcat.addServlet(ctx, "bus", rest);
wrapper.setLoadOnStartup(1);
- ctx.addServletMappingDecoded("/rest/*", "bus");
+ wrapper.addMapping("/rest/*");
ctx.addApplicationListener(org.apache.tomcat.websocket.server.WsContextListener.class.getName());
tomcat.start();
var sc = (ServerContainer) ctx.getServletContext().getAttribute(ServerContainer.class.getName());
@@ -346,9 +349,8 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
*/
@Test void a04_hostOriginMismatchCloses4403() throws Exception {
var path = openSession(HttpClient.newHttpClient());
- try (var socket = new Socket("127.0.0.1", plainPort)) {
+ try (var socket = new Socket("127.0.0.1", plainPort); var out = socket.getOutputStream(); var in = new BufferedInputStream(socket.getInputStream())) {
socket.setSoTimeout(10_000);
- var out = socket.getOutputStream();
out.write(("GET " + path + " HTTP/1.1\r\n"
+ "Host: evil.example\r\n"
+ "Origin: " + origin(plainPort) + "\r\n"
@@ -357,7 +359,6 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
+ "Sec-WebSocket-Version: 13\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n").getBytes(StandardCharsets.US_ASCII));
out.flush();
- var in = new BufferedInputStream(socket.getInputStream());
var head = new StringBuilder();
while (! head.toString().endsWith("\r\n\r\n")) {
var b = in.read();
@@ -439,9 +440,8 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
*/
@Test void a09_repeatedForwardedHostLinesKeepWireOrder() throws Exception {
FORWARDED_HOSTS.clear();
- try (var socket = new Socket("127.0.0.1", plainPort)) {
+ try (var socket = new Socket("127.0.0.1", plainPort); var out = socket.getOutputStream()) {
socket.setSoTimeout(10_000);
- var out = socket.getOutputStream();
out.write(("GET /probe HTTP/1.1\r\n"
+ "Host: 127.0.0.1:" + plainPort + "\r\n"
+ "X-Forwarded-Host: first.example\r\n"
@@ -550,11 +550,10 @@ class BusWebSocketCsrf_TomcatIT extends TestBase {
var seen = new StringBuilder();
var settings = false;
var advertised = false;
- try (var socket = new Socket("127.0.0.1", port)) {
+ try (var socket = new Socket("127.0.0.1", port); var in = new DataInputStream(socket.getInputStream())) {
socket.setSoTimeout(3_000);
socket.getOutputStream().write(out.toByteArray());
socket.getOutputStream().flush();
- var in = new DataInputStream(socket.getInputStream());
try {
for (;;) {
var head = new byte[9];
diff --git a/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/ServletFilterRegistration_TomcatMount_Test.java b/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/ServletFilterRegistration_TomcatMount_Test.java
index 4fec6c312f..efc8d4c9c8 100644
--- a/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/ServletFilterRegistration_TomcatMount_Test.java
+++ b/juneau-microservice/juneau-microservice-tomcat/src/test/java/org/apache/juneau/microservice/tomcat/ServletFilterRegistration_TomcatMount_Test.java
@@ -47,6 +47,7 @@ import jakarta.servlet.http.*;
@org.apache.juneau.testing.TomcatMicroserviceTest
@SuppressWarnings({
"java:S1192", // Repeated URL pattern and tag literals keep each test self-contained and readable.
+ "java:S3415", // Expected value is already first; Sonar misreads the upper-case LOG constant as the expected argument
"resource" // Microservice instances are test fixtures managed by the test lifecycle; explicit close is not needed for these assertions.
})
class ServletFilterRegistration_TomcatMount_Test extends TestBase {
@@ -524,8 +525,11 @@ class ServletFilterRegistration_TomcatMount_Test extends TestBase {
try {
start(ms);
var c = ms.getBeanStore().getBean(TomcatServerComponent.class).orElseThrow();
- assertThrows(IllegalStateException.class, () -> c.addFilter(new Recorder("L"), EnumSet.of(DispatcherType.REQUEST), "/hello/*"));
- assertThrows(IllegalStateException.class, () -> c.addFilter(ServletFilterRegistration.create(new Recorder("L")).urlPatterns("/hello/*").build()));
+ var late = new Recorder("L");
+ var req = EnumSet.of(DispatcherType.REQUEST);
+ var registration = ServletFilterRegistration.create(late).urlPatterns("/hello/*").build();
+ assertThrows(IllegalStateException.class, () -> c.addFilter(late, req, "/hello/*"));
+ assertThrows(IllegalStateException.class, () -> c.addFilter(registration));
} finally {
ms.stop();
}
@@ -541,7 +545,8 @@ class ServletFilterRegistration_TomcatMount_Test extends TestBase {
assertThrows(IllegalArgumentException.class, () -> c.addFilter(null, req, "/a/*"));
assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, req));
assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, req, "/console*"));
- assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, EnumSet.noneOf(DispatcherType.class), "/a/*"));
+ var none = EnumSet.noneOf(DispatcherType.class);
+ assertThrows(IllegalArgumentException.class, () -> c.addFilter(f, none, "/a/*"));
assertThrows(IllegalArgumentException.class, () -> c.addFilter((ServletFilterRegistration)null));
} finally {
ms.stop();
diff --git a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
index 7807eaf8dc..ad29df7a73 100755
--- a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
+++ b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
@@ -1178,9 +1178,9 @@ public class Microservice implements ConfigEventListener {
mkdirs(logDirFile, false);
logDir = logDirFile.getAbsolutePath();
// Intentional real-JVM-property publish: the resolved log directory is exposed as a process-global
- // system property so external config/templates can reference it via the raw-reading $S{juneau.logDir}
- // SVL var (SystemPropertiesVar reads System.getProperty directly, bypassing the Settings override
- // chain). A Settings-based write would not be visible to $S{...}, so this is kept.
+ // system property so external config and templates can reference it through the raw-reading
+ // juneau.logDir SVL variable. That variable reads the JVM property directly and bypasses the
+ // Settings override chain, so a Settings-based write would not be visible to it.
System.setProperty("juneau.logDir", logDir);
var append = coalesce(logConfig.append, config.get("Logging/append").asBoolean().orElse(false));
diff --git a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/ServletFilterRegistration.java b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/ServletFilterRegistration.java
index 36a44b73d5..f2453e5e71 100644
--- a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/ServletFilterRegistration.java
+++ b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/ServletFilterRegistration.java
@@ -19,6 +19,7 @@ package org.apache.juneau.microservice;
import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
+import java.util.stream.*;
import org.apache.juneau.commons.inject.*;
import org.apache.juneau.rest.server.auth.*;
@@ -220,15 +221,33 @@ public final class ServletFilterRegistration {
public ServletFilterRegistration build() {
if (urlPatterns.isEmpty())
throw iaex("A servlet filter registration needs at least one URL pattern.");
- var patterns = new LinkedHashSet<String>();
- for (var p : urlPatterns)
- patterns.add(validatePattern(p));
+ urlPatterns.forEach(Builder::validatePattern);
+ var patterns = new LinkedHashSet<>(urlPatterns);
if (dispatcherTypes.isEmpty())
throw iaex("A servlet filter registration needs at least one dispatcher type.");
if (dispatcherTypes.contains(null))
throw iaex("A dispatcher type must not be null.");
return new ServletFilterRegistration(this, List.copyOf(patterns), Collections.unmodifiableSet(EnumSet.copyOf(dispatcherTypes)));
}
+
+ private static void validatePattern(String p) {
+ if (p == null || (! p.isEmpty() && p.isBlank()))
+ throw iaex("A URL pattern must not be null or blank.");
+ if (p.isEmpty())
+ return;
+ if (p.startsWith("regex:") || p.startsWith("^") || p.startsWith("uri-template:"))
+ throw iaex("URL pattern '%s' uses container-specific path-spec syntax; use a path prefix, an extension or an exact path.", p);
+ if (p.equals("/"))
+ throw iaex("URL pattern '/' maps to the default servlet and is not accepted for a filter; use '/*'.");
+ var star = p.indexOf('*');
+ if (p.startsWith("/")) {
+ if (star < 0 || (star == p.length() - 1 && p.endsWith("/*")))
+ return;
+ } else if (p.startsWith("*.") && p.length() > 2 && star == 0 && p.lastIndexOf('*') == 0 && p.indexOf('/') < 0) {
+ return;
+ }
+ throw iaex("URL pattern '%s' is not valid: use a path prefix like '/console/*', an extension like '*.json', or an exact path like '/console'.", p);
+ }
}
/**
@@ -263,9 +282,9 @@ public final class ServletFilterRegistration {
public static List<ServletFilterRegistration> collect(BeanStore store) {
if (store == null)
throw iaex("store must not be null.");
- var entries = new ArrayList<Entry>();
- for (var e : store.getBeansOfType(ServletFilterRegistration.class).entrySet())
- entries.add(new Entry(e.getValue(), e.getKey()));
+ var entries = store.getBeansOfType(ServletFilterRegistration.class).entrySet().stream()
+ .map(e -> new Entry(e.getValue(), e.getKey()))
+ .collect(Collectors.toCollection(ArrayList::new));
store.getBean(AuthFilterChain.class).ifPresent(chain -> {
if (entries.stream().noneMatch(e -> e.registration.filter == chain))
@@ -302,25 +321,6 @@ public final class ServletFilterRegistration {
}
}
- private static String validatePattern(String p) {
- if (p == null || (! p.isEmpty() && p.isBlank()))
- throw iaex("A URL pattern must not be null or blank.");
- if (p.isEmpty())
- return p;
- if (p.startsWith("regex:") || p.startsWith("^") || p.startsWith("uri-template:"))
- throw iaex("URL pattern '%s' uses container-specific path-spec syntax; use a path prefix, an extension or an exact path.", p);
- if (p.equals("/"))
- throw iaex("URL pattern '/' maps to the default servlet and is not accepted for a filter; use '/*'.");
- var star = p.indexOf('*');
- if (p.startsWith("/")) {
- if (star < 0 || (star == p.length() - 1 && p.endsWith("/*")))
- return p;
- } else if (p.startsWith("*.") && p.length() > 2 && star == 0 && p.lastIndexOf('*') == 0 && p.indexOf('/') < 0) {
- return p;
- }
- throw iaex("URL pattern '%s' is not valid: use a path prefix like '/console/*', an extension like '*.json', or an exact path like '/console'.", p);
- }
-
private final Filter filter;
private final List<String> urlPatterns;
private final Set<DispatcherType> dispatcherTypes;
diff --git a/juneau-microservice/juneau-microservice/src/test/java/org/apache/juneau/microservice/ServletFilterRegistration_Test.java b/juneau-microservice/juneau-microservice/src/test/java/org/apache/juneau/microservice/ServletFilterRegistration_Test.java
index e3b39bca6d..81060d5293 100644
--- a/juneau-microservice/juneau-microservice/src/test/java/org/apache/juneau/microservice/ServletFilterRegistration_Test.java
+++ b/juneau-microservice/juneau-microservice/src/test/java/org/apache/juneau/microservice/ServletFilterRegistration_Test.java
@@ -33,7 +33,8 @@ import jakarta.servlet.*;
* {@link ServletFilterRegistration#collect(BeanStore)}.
*/
@SuppressWarnings({
- "java:S1192" // Repeated URL pattern literals keep each test self-contained and readable.
+ "java:S1192", // Repeated URL pattern literals keep each test self-contained and readable.
+ "resource" // BasicBeanStore is a fluent AutoCloseable; the in-memory test stores hold nothing to close and addBean self-returns are not new resources.
})
class ServletFilterRegistration_Test extends TestBase {
@@ -81,8 +82,10 @@ class ServletFilterRegistration_Test extends TestBase {
@Test void a04_collections_unmodifiable() {
var r = ServletFilterRegistration.create(F).urlPatterns("/a/*").build();
- assertThrows(UnsupportedOperationException.class, () -> r.getUrlPatterns().add("/x"));
- assertThrows(UnsupportedOperationException.class, () -> r.getDispatcherTypes().add(DispatcherType.ERROR));
+ var patterns = r.getUrlPatterns();
+ var types = r.getDispatcherTypes();
+ assertThrows(UnsupportedOperationException.class, () -> patterns.add("/x"));
+ assertThrows(UnsupportedOperationException.class, () -> types.add(DispatcherType.ERROR));
}
@Test void a05_optionsRoundTrip() {
@@ -101,14 +104,19 @@ class ServletFilterRegistration_Test extends TestBase {
}
@Test void b02_noPatterns() {
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).build());
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns().build());
+ var none = ServletFilterRegistration.create(F);
+ var empty = ServletFilterRegistration.create(F).urlPatterns();
+ assertThrows(IllegalArgumentException.class, none::build);
+ assertThrows(IllegalArgumentException.class, empty::build);
}
@Test void b03_nullOrBlankPattern() {
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns((String)null).build());
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns("/a/*", " ").build());
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns("\t").build());
+ var nullPattern = ServletFilterRegistration.create(F).urlPatterns((String)null);
+ var blankPattern = ServletFilterRegistration.create(F).urlPatterns("/a/*", " ");
+ var tabPattern = ServletFilterRegistration.create(F).urlPatterns("\t");
+ assertThrows(IllegalArgumentException.class, nullPattern::build);
+ assertThrows(IllegalArgumentException.class, blankPattern::build);
+ assertThrows(IllegalArgumentException.class, tabPattern::build);
}
@Test void b03a_emptyPattern_isTheContextRoot() {
@@ -122,7 +130,8 @@ class ServletFilterRegistration_Test extends TestBase {
@Test void b05_invalidPatterns() {
for (var p : new String[]{"/", "console/*", "/console*", "/a/*/b", "*.", "*.a/b", "a*.x", "regex:/a.*", "^/a", "uri-template:/a/{x}", "/a/**", "*", "*.*", "*.a*"}) {
- var ex = assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns(p).build(), p);
+ var b = ServletFilterRegistration.create(F).urlPatterns(p);
+ var ex = assertThrows(IllegalArgumentException.class, b::build, p);
assertTrue(ex.getMessage().contains("'" + p + "'"), "Message should name the pattern: " + ex.getMessage());
}
}
@@ -139,11 +148,13 @@ class ServletFilterRegistration_Test extends TestBase {
}
@Test void b06_noDispatcherTypes() {
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns("/a/*").dispatcherTypes().build());
+ var b = ServletFilterRegistration.create(F).urlPatterns("/a/*").dispatcherTypes();
+ assertThrows(IllegalArgumentException.class, b::build);
}
@Test void b07_nullDispatcherType() {
- assertThrows(IllegalArgumentException.class, () -> ServletFilterRegistration.create(F).urlPatterns("/a/*").dispatcherTypes(DispatcherType.REQUEST, null).build());
+ var b = ServletFilterRegistration.create(F).urlPatterns("/a/*").dispatcherTypes(DispatcherType.REQUEST, null);
+ assertThrows(IllegalArgumentException.class, b::build);
}
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/PetstoreApiBoundary.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/PetstoreApiBoundary.java
index 62858108c2..c243105ccb 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/PetstoreApiBoundary.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/PetstoreApiBoundary.java
@@ -71,7 +71,7 @@ import jakarta.servlet.http.*;
* <p>
* Behind a TLS-terminating proxy the browser's {@code https} origin does not match the {@code http} request the
* container sees, so writes are refused. Such a deployment needs the container's forwarded-header support and the
- * framework boundary's {@link CsrfBoundary.OriginSource#CONTAINER CONTAINER} origin source, which this demo does not
+ * framework boundary's {@link org.apache.juneau.rest.server.filter.CsrfBoundary.OriginSource#CONTAINER CONTAINER} origin source, which this demo does not
* configure.
*
* <h5 class='section'>Example:</h5>
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/StoreRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/StoreRest.java
index c04fe650b4..53c251b930 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/StoreRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/StoreRest.java
@@ -143,8 +143,7 @@ public class StoreRest extends PetstoreConsolePage {
public JsonList species() {
var counts = store().getPets().stream().filter(p -> p.getSpecies() != null).collect(Collectors.groupingBy(Pet::getSpecies, Collectors.counting()));
var rows = new JsonList();
- for (var s : Species.values())
- rows.add(JsonMap.of("species", s.name(), "count", counts.getOrDefault(s, 0L)));
+ Arrays.stream(Species.values()).forEach(s -> rows.add(JsonMap.of("species", s.name(), "count", counts.getOrDefault(s, 0L))));
return rows;
}
@@ -153,8 +152,7 @@ public class StoreRest extends PetstoreConsolePage {
public JsonList status() {
var counts = store().getPets().stream().filter(p -> p.getStatus() != null).collect(Collectors.groupingBy(Pet::getStatus, Collectors.counting()));
var rows = new JsonList();
- for (var s : PetStatus.values())
- rows.add(JsonMap.of("status", s.name(), "count", counts.getOrDefault(s, 0L)));
+ Arrays.stream(PetStatus.values()).forEach(s -> rows.add(JsonMap.of("status", s.name(), "count", counts.getOrDefault(s, 0L))));
return rows;
}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/CustomCardsRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/CustomCardsRest.java
index 1378b6b3c1..c4541ec79c 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/CustomCardsRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/CustomCardsRest.java
@@ -115,8 +115,7 @@ public class CustomCardsRest extends PetstoreConsolePage {
@RestGet(path="/inventory/all")
public JsonList inventoryAll() {
var rows = new JsonList();
- for (var s : Species.values())
- rows.add(inventory(s.name()));
+ Arrays.stream(Species.values()).forEach(s -> rows.add(inventory(s.name())));
return rows;
}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/DashboardRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/DashboardRest.java
index b9191ba22b..dd9b21ac34 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/DashboardRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/DashboardRest.java
@@ -96,14 +96,16 @@ public class DashboardRest extends PetstoreConsolePage {
* @throws IOException If the response can't be written.
*/
@RestGet(path="/series/{variant}")
+ @SuppressWarnings({
+ "java:S3776" // Branching is inherent to the demo source's variants.
+ })
public void series(RestRequest req, RestResponse res, @Path("variant") String variant, @Query("q") @Schema(aev=true) String q,
@Query("start") String start, @Query("end") String end, @Query("lateOnly") String lateOnly) throws IOException {
SERIES_REQUESTS.incrementAndGet();
if ("error".equals(variant))
throw new InternalServerError("The demo source failed on purpose (variant=error).");
var reasons = new HashSet<String>();
- for (var p : req.getQueryParams().getAll("reasons"))
- reasons.add(p.getValue());
+ req.getQueryParams().getAll("reasons").forEach(p -> reasons.add(p.getValue()));
var e = instant(end, LocalDate.now(ZoneOffset.UTC).plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant());
var s = instant(start, e.minus(Duration.ofDays(30)));
if (s.isBefore(e.minus(MAX_WINDOW)))
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType.java
index 3acf3fb3da..624714b88b 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType.java
@@ -41,6 +41,9 @@ import org.apache.juneau.rest.server.console.*;
* ConsoleFreemarkerMixin.<jsm>create</jsm>().cardType(<jk>new</jk> InventoryGaugeCardType()).build();
* </p>
*/
+@SuppressWarnings({
+ "java:S1845" // type() returns the public TYPE constant; the shared name is intentional
+})
public class InventoryGaugeCardType implements CardTypeHandler {
/** The card type name. */
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/GroomRuns.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/GroomRuns.java
index 02ee3f7c57..a4bae1e022 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/GroomRuns.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/GroomRuns.java
@@ -51,7 +51,8 @@ import org.apache.juneau.rest.server.terminal.*;
* </p>
*/
@SuppressWarnings({
- "java:S1192" // The script's literals are demo text; constants would obscure it.
+ "java:S1192", // The script's literals are demo text; constants would obscure it.
+ "resource" // Each Run owns its file-backed source, closed by drop()/close(); seeded() hands the new GroomRuns to its caller.
})
public final class GroomRuns implements AutoCloseable {
@@ -68,7 +69,10 @@ public final class GroomRuns implements AutoCloseable {
static final int RING_BYTES = 1 << 20;
/** The terminal size, in columns and rows, of both of a run's terminals. */
- static final int COLS = 100, ROWS = 24;
+ static final int COLS = 100;
+
+ /** The terminal height, in rows, of both of a run's terminals. */
+ static final int ROWS = 24;
private static final String RESET = "\u001b[0m";
private static final String BOLD = "\u001b[1m";
@@ -120,7 +124,7 @@ public final class GroomRuns implements AutoCloseable {
final AtomicInteger lines = new AtomicInteger();
final AtomicInteger step = new AtomicInteger();
volatile boolean done;
- volatile ScheduledFuture<?> task;
+ final AtomicReference<ScheduledFuture<?>> task = new AtomicReference<>();
volatile String key;
Run(String id, String pet, boolean verbose, Path file) {
@@ -214,6 +218,9 @@ public final class GroomRuns implements AutoCloseable {
* @return The run.
* @throws IOException If the temp file cannot be created.
*/
+ @SuppressWarnings({
+ "java:S5443" // Files.createTempFile creates the file owner-only (rw-------) on POSIX
+ })
public Run start(String pet, boolean verbose, String idempotencyKey) throws IOException {
synchronized (order) {
if (idempotencyKey != null) {
@@ -239,7 +246,7 @@ public final class GroomRuns implements AutoCloseable {
}
while (order.size() > MAX_RUNS)
drop(order.removeLast());
- r.task = ticker.scheduleAtFixedRate(() -> tick(r), periodMs, periodMs, TimeUnit.MILLISECONDS);
+ r.task.set(ticker.scheduleAtFixedRate(() -> tick(r), periodMs, periodMs, TimeUnit.MILLISECONDS));
return r;
}
}
@@ -308,13 +315,13 @@ public final class GroomRuns implements AutoCloseable {
r.done = true;
r.terminal.finish();
r.fileDone.set(true);
- var t = r.task;
+ var t = r.task.get();
if (t != null)
t.cancel(false);
}
private void drop(Run r) {
- var t = r.task;
+ var t = r.task.get();
if (t != null)
t.cancel(false);
runs.remove(r.id);
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/JobsRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/JobsRest.java
index 24b7ed85a0..492e2e3b60 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/JobsRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/ops/JobsRest.java
@@ -22,6 +22,7 @@ import java.io.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
import java.util.function.*;
import org.apache.juneau.commons.inject.*;
@@ -97,7 +98,7 @@ public class JobsRest extends PetstoreConsolePage implements AsyncJobsMixin, Ter
/** Where this resource is mounted; the terminal URLs are built from it. */
public static final String MOUNT = "/console/ops/jobs";
- private static final String GROOM = "groom";
+ private static final String GROOM_JOB = "groom";
/** The species row's restock action; its keys come from the ledger, bound to the species and the caller. */
static final String RESTOCK_SPECIES = "restock-species";
@@ -163,7 +164,7 @@ public class JobsRest extends PetstoreConsolePage implements AsyncJobsMixin, Ter
@Bean
private transient KeyClock keyClock;
- private transient volatile AsyncJobRegistry jobs;
+ private final transient AtomicReference<AsyncJobRegistry> jobs = new AtomicReference<>();
private final transient ExecutorService pool = Executors.newCachedThreadPool(r -> {
var t = new Thread(r, "petstore-restock");
t.setDaemon(true);
@@ -254,12 +255,14 @@ public class JobsRest extends PetstoreConsolePage implements AsyncJobsMixin, Ter
@Override /* AsyncJobsMixin */
public AsyncJobRegistry asyncJobRegistry() {
- var j = jobs;
+ var j = jobs.get();
if (j == null) {
synchronized (this) {
- j = jobs;
- if (j == null)
- jobs = j = new AsyncJobRegistry(hardTimeout == null ? DEFAULT_HARD_TIMEOUT : hardTimeout.value());
+ j = jobs.get();
+ if (j == null) {
+ j = new AsyncJobRegistry(hardTimeout == null ? DEFAULT_HARD_TIMEOUT : hardTimeout.value());
+ jobs.set(j);
+ }
}
}
return j;
@@ -271,8 +274,9 @@ public class JobsRest extends PetstoreConsolePage implements AsyncJobsMixin, Ter
@RestDestroy
public void closeJobs() {
pool.shutdownNow();
- if (jobs != null)
- jobs.close();
+ var j = jobs.get();
+ if (j != null)
+ j.close();
groom.close();
}
@@ -480,7 +484,7 @@ public class JobsRest extends PetstoreConsolePage implements AsyncJobsMixin, Ter
form.field(FormDef.Input.of("pet", "Pet name", "text").value("Rex"));
form.field(FormDef.Input.of("verbose", "Verbose (8000 extra lines)", "checkbox"));
return ModalDef.create("Groom a pet").form(form)
- .idempotencyKey(IdempotencyKey.mintSelfTargeted(GROOM).value()).selfTargeted(true);
+ .idempotencyKey(IdempotencyKey.mintSelfTargeted(GROOM_JOB).value()).selfTargeted(true);
}
/**
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/orders/OrdersRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/orders/OrdersRest.java
index 21e0c565d3..2b07401a83 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/orders/OrdersRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/orders/OrdersRest.java
@@ -22,7 +22,6 @@ import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
-import org.apache.juneau.commons.bean.*;
import org.apache.juneau.commons.beanquery.*;
import org.apache.juneau.commons.Schema;
import org.apache.juneau.http.*;
@@ -60,7 +59,8 @@ import org.apache.juneau.rest.server.widgets.*;
*/
@Rest(path="/orders", title="Orders")
@SuppressWarnings({
- "java:S110" // Inheritance depth comes from the BasicRestServlet hierarchy, not this page.
+ "java:S110", // Inheritance depth comes from the BasicRestServlet hierarchy, not this page.
+ "java:S1192" // Route paths and field names repeat as inline literals by design.
})
public class OrdersRest extends PetstoreConsolePage {
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/ChangesPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/ChangesPageBuilders.java
index 3144e234ff..b1a52e0c75 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/ChangesPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/ChangesPageBuilders.java
@@ -30,6 +30,9 @@ import org.apache.juneau.rest.server.widgets.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, ChangesPageBuilders.<jsm>changes</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class ChangesPageBuilders {
private ChangesPageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/DevPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/DevPageBuilders.java
index cc8be016a0..d1c6da8c32 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/DevPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/DevPageBuilders.java
@@ -41,6 +41,9 @@ import org.apache.juneau.rest.server.views.TableSpec.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, DevPageBuilders.<jsm>secure</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class DevPageBuilders {
private DevPageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OpsPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OpsPageBuilders.java
index 9fa4707933..143e81db1d 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OpsPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OpsPageBuilders.java
@@ -33,6 +33,9 @@ import org.apache.juneau.rest.server.views.TableSpec.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, OpsPageBuilders.<jsm>audit</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class OpsPageBuilders {
private OpsPageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OrdersPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OrdersPageBuilders.java
index 66f0d09fba..3ade2a3132 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OrdersPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/OrdersPageBuilders.java
@@ -31,6 +31,9 @@ import org.apache.juneau.rest.server.views.TableSpec.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, OrdersPageBuilders.<jsm>orders</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class OrdersPageBuilders {
private OrdersPageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/PetsPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/PetsPageBuilders.java
index 086bd505ba..427add0092 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/PetsPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/PetsPageBuilders.java
@@ -36,6 +36,9 @@ import org.apache.juneau.rest.server.widgets.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, PetsPageBuilders.<jsm>pets</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class PetsPageBuilders {
/**
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/StorePageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/StorePageBuilders.java
index f36ec2412b..9f18d5a482 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/StorePageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/StorePageBuilders.java
@@ -34,6 +34,9 @@ import org.apache.juneau.rest.server.widgets.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, StorePageBuilders.<jsm>store</jsm>(QuickStats.<jsm>of</jsm>(store())));
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class StorePageBuilders {
private StorePageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/UsersPageBuilders.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/UsersPageBuilders.java
index 71be599b85..08d5496e72 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/UsersPageBuilders.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pages/UsersPageBuilders.java
@@ -29,6 +29,9 @@ import org.apache.juneau.rest.server.views.TableSpec.*;
* <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, UsersPageBuilders.<jsm>users</jsm>());
* </p>
*/
+@SuppressWarnings({
+ "java:S1192" // Page-definition ids and labels repeat as inline literals by design.
+})
public final class UsersPageBuilders {
private UsersPageBuilders() {}
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pets/PetsRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pets/PetsRest.java
index a492335ce6..d4c5df7793 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pets/PetsRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/pets/PetsRest.java
@@ -158,6 +158,9 @@ public class PetsRest extends PetstoreConsolePage {
}
/** The usable ids in a comma-separated value, or {@code null} if there are none (no filter). */
+ @SuppressWarnings({
+ "java:S1168" // null means no filter, distinct from an empty id set
+ })
private static Set<Long> parseIds(String value) {
if (value == null)
return null;
diff --git a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/users/UsersRest.java b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/users/UsersRest.java
index 79f13b41ca..942f095445 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/users/UsersRest.java
+++ b/juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/users/UsersRest.java
@@ -50,7 +50,8 @@ import org.apache.juneau.rest.server.widgets.*;
*/
@Rest(path="/users", title="Users")
@SuppressWarnings({
- "java:S110" // Inheritance depth comes from the BasicRestServlet hierarchy, not this page.
+ "java:S110", // Inheritance depth comes from the BasicRestServlet hierarchy, not this page.
+ "java:S1192" // Route paths and field names repeat as inline literals by design.
})
public class UsersRest extends PetstoreConsolePage {
diff --git a/juneau-petstore/juneau-petstore-core/src/main/resources/org/apache/juneau/petstore/console/petstore.js b/juneau-petstore/juneau-petstore-core/src/main/resources/org/apache/juneau/petstore/console/petstore.js
index 35b37aecfd..83f10bd331 100644
--- a/juneau-petstore/juneau-petstore-core/src/main/resources/org/apache/juneau/petstore/console/petstore.js
+++ b/juneau-petstore/juneau-petstore-core/src/main/resources/org/apache/juneau/petstore/console/petstore.js
@@ -19,18 +19,18 @@
// P4 Photo tab: submit the upload form as a PUT to the API's own photo endpoint, then reload; a failure stays on the page.
// The upload carries the API's CSRF token (stamped on the form by the server) in the API's token header.
document.addEventListener('submit', function(e) {
- var form = e.target.closest ? e.target.closest('form[data-petstore-upload]') : null;
+ const form = e.target.closest ? e.target.closest('form[data-petstore-upload]') : null;
if (!form)
return;
e.preventDefault();
- var file = form.querySelector('input[type=file]').files[0];
+ const file = form.querySelector('input[type=file]').files[0];
if (!file)
return;
- var headers = { 'Content-Type': file.type, 'Accept': 'text/plain' };
- var csrf = form.getAttribute('data-petstore-csrf');
- if (csrf !== null)
+ const headers = { 'Content-Type': file.type, 'Accept': 'text/plain' };
+ const csrf = form.dataset.petstoreCsrf;
+ if (csrf !== undefined)
headers['X-Csrf-Token'] = csrf;
- fetch(form.getAttribute('data-petstore-upload'), { method: 'PUT', headers: headers, body: file })
+ fetch(form.dataset.petstoreUpload, { method: 'PUT', headers: headers, body: file })
.then(function(r) {
if (r.ok)
return window.location.reload();
@@ -41,15 +41,15 @@
// The toolkit's status line under the form (JuneauViews.status), or a plain alert paragraph without the toolkit.
function showError(form, message) {
- var views = window.JuneauViews;
- if (views && views.status) {
+ const views = window.JuneauViews;
+ if (views?.status) {
views.status.render(form, 'error', message);
return;
}
- var p = form.querySelector('p[data-petstore-error]');
+ let p = form.querySelector('p[data-petstore-error]');
if (!p) {
p = document.createElement('p');
- p.setAttribute('data-petstore-error', '');
+ p.dataset.petstoreError = '';
p.setAttribute('role', 'alert');
form.appendChild(p);
}
@@ -59,40 +59,45 @@
// R10: a typed-confirmation renderer. A renderer is fn(modal, request) and paints its own UI; it returns a Promise
// of true to proceed. The user types the expected value (the row id, or the selected count for an aggregate bulk
// action) before Confirm enables.
- var views = window.JuneauViews;
- if (views && views.rowActions && views.rowActions.registerConfirmRenderer) {
+ const views = window.JuneauViews;
+ if (views?.rowActions?.registerConfirmRenderer) {
views.rowActions.registerConfirmRenderer('typed', function(modal, request) {
- var rows = request.rows || [];
- var idField = request.rowIdField || 'id';
+ const rows = request.rows || [];
+ const idField = request.rowIdField || 'id';
// One row (a per-row or single-selection action): type its id. Several: type the count. A ribbon-hosted
// action has no row, so it types the action's own id.
- var raw = rows.length > 1 ? rows.length
- : rows.length ? rows[0][idField] : request.action && request.action.id;
+ let raw;
+ if (rows.length > 1)
+ raw = rows.length;
+ else if (rows.length)
+ raw = rows[0][idField];
+ else
+ raw = request.action?.id;
// Fail closed: a missing, null or blank value (no action id, or a row without a usable id) would otherwise
// become '' (an empty input satisfies the gate), 'undefined' or 'null' (a nonsense word to type). A typed
// gate with nothing meaningful to type is no gate, so refuse with a warning instead of opening a dialog.
- var expected = raw == null ? '' : String(raw);
+ const expected = raw == null ? '' : String(raw);
if (expected.trim() === '') {
console.warn('[petstore] typed confirm refused: nothing to type (no usable row id or action id)');
return Promise.resolve(false);
}
return new Promise(function(resolve) {
- var dlg = document.createElement('dialog');
+ const dlg = document.createElement('dialog');
dlg.className = 'jc-dialog petstore-typed-confirm';
- var h = document.createElement('h2');
+ const h = document.createElement('h2');
h.textContent = modal.title;
- var p = document.createElement('p');
+ const p = document.createElement('p');
p.textContent = modal.body || '';
- var input = document.createElement('input');
+ const input = document.createElement('input');
input.type = 'text';
input.className = 'jc-input';
input.setAttribute('aria-label', 'Type ' + expected + ' to confirm');
- var ok = document.createElement('button');
+ const ok = document.createElement('button');
ok.type = 'button';
ok.className = 'jc-button petstore-typed-confirm-ok';
ok.textContent = modal.confirmLabel;
ok.disabled = true;
- var cancel = document.createElement('button');
+ const cancel = document.createElement('button');
cancel.type = 'button';
cancel.className = 'jc-button petstore-typed-confirm-cancel';
cancel.textContent = modal.cancelLabel;
@@ -111,7 +116,7 @@
// Jobs page: a groom run's detail panel offers "Groom again". The button runs through JuneauViews.jobs, which fetches
// a key bound to this run from the key endpoint and fills {id} from the panel's parent row.
- if (views && views.regions && views.regions.register) {
+ if (views?.regions?.register) {
views.regions.register('petstore-regroom', function(ctx, container) {
container.appendChild(ctx.helpers.jobButton({
label: 'Groom again',
@@ -125,7 +130,7 @@
// R10: a compact dialog chrome, selected by a modal's chrome:'compact'. fn(parts, modal) restyles the dialog parts.
// The new-order wizard (both steps) opts in with ModalDef.chrome("compact").
- if (views && views.dialogs && views.dialogs.registerChrome) {
+ if (views?.dialogs?.registerChrome) {
views.dialogs.registerChrome('compact', function(parts) {
parts.dialog.classList.add('petstore-dialog-compact');
});
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreAssets_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreAssets_Test.java
index 3791c3bf7e..7804774d7e 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreAssets_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreAssets_Test.java
@@ -105,7 +105,7 @@ class PetstoreAssets_Test extends TestBase {
C.get(url).run().assertStatus(200).assertHeader("Content-Type").asString().isContains("javascript");
}
- @Test void b04_aPathOutsideTheWebJarsDoesNotResolve() throws Exception {
+ @Test void b04_aPathOutsideTheWebJarsDoesNotResolve() {
org.junit.jupiter.api.Assertions.assertEquals(404, status("/console/ops/audit/webjars/../x"));
org.junit.jupiter.api.Assertions.assertEquals(404, status("/console/ops/audit/webjars/no-such/file.js"));
org.junit.jupiter.api.Assertions.assertEquals(404, status("/console/vendor/jquery/3.7.1/jquery.min.js"));
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreFailLoud_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreFailLoud_Test.java
index eb99af4e6d..f7501c6cf9 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreFailLoud_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreFailLoud_Test.java
@@ -149,6 +149,9 @@ class PetstoreFailLoud_Test extends TestBase {
assert500("malformed-json5", "Card JSON5 is invalid:");
}
+ @SuppressWarnings({
+ "java:S5778" // The reserved-type rejection may come from either cardType(...) or build(); the lambda must cover both
+ })
@Test void a15_adopterHandlerForAReservedType_failsAtMixinBuild() {
var ex = assertThrows(IllegalArgumentException.class,
() -> ConsoleFreemarkerMixin.create().cardType(new ImpostorDatatables()).build());
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreTwins_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreTwins_Test.java
index 5cde536c43..80e367f2c5 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreTwins_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/PetstoreTwins_Test.java
@@ -67,8 +67,7 @@ class PetstoreTwins_Test extends TestBase {
@ParameterizedTest(name="{0}")
@MethodSource("twins")
void a01_ftlEqualsBuilder(String path) throws Exception {
- var c = client();
- assertSameContract(path, ftl(c, path), builder(c, path));
+ assertFull(path);
}
// A plain loop, not a parameterized test: JUnit rejects an empty source, and GAPS is empty when no gaps are known.
@@ -86,8 +85,10 @@ class PetstoreTwins_Test extends TestBase {
var builderContract = builder.contract();
var builderTemplates = new TreeMap<>(builder.templates());
for (var d : g.dropped()) {
- // | not ||: drop from both sides.
- var dropped = drop(contract, templates, d) | drop(builderContract, builderTemplates, d);
+ // Drop from both sides, whether or not the first side had it.
+ var droppedFtl = drop(contract, templates, d);
+ var droppedBuilder = drop(builderContract, builderTemplates, d);
+ var dropped = droppedFtl || droppedBuilder;
assertTrue(dropped, () -> "nothing to drop at '" + d + "' on either side of '" + g.path() + "'");
}
assertTwinsAt(g.path(), contract, templates, builderContract, builderTemplates);
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreConsoleWrites_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreConsoleWrites_BrowserTest.java
index 7a85afc30b..21f72724aa 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreConsoleWrites_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreConsoleWrites_BrowserTest.java
@@ -50,6 +50,9 @@ import jakarta.servlet.http.*;
@Covers(value="inline-edit", pages="/console/pets/1/summary")
@HookCovers("status")
@EnabledIfSystemProperty(named=PetstoreBrowser.GATE, matches="true", disabledReason=PetstoreBrowser.DISABLED)
+@SuppressWarnings({
+ "resource" // The connector belongs to the attacker server, which closes it; servlet response writers belong to the container.
+})
class PetstoreConsoleWrites_BrowserTest extends TestBase {
@RegisterExtension
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreOrderWizard_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreOrderWizard_BrowserTest.java
index fffecbe877..e447d065af 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreOrderWizard_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreOrderWizard_BrowserTest.java
@@ -63,7 +63,7 @@ class PetstoreOrderWizard_BrowserTest extends TestBase {
private static Map<String,Map<String,Object>> report;
/** One full pass through the wizard at the given viewport, shipping on the given date. */
- private static Map<String,Object> wizard(String name, List<Integer> viewport, String shipDate, String shown) {
+ private static Map<String,Object> wizard(String name, List<Integer> viewport, String shipDate) {
return Map.of("name", name, "path", "/console/orders", "capture", "/console/orders", "viewport", viewport,
"actions", List.of(
wait(NEW_ORDER + " && " + ROWS + " > 0"),
@@ -110,8 +110,8 @@ class PetstoreOrderWizard_BrowserTest extends TestBase {
static void probe() throws Exception {
var base = PetstoreTestServer.awaitReady(server);
report = run("order-wizard", base, List.of(
- wizard("wide", List.of(1280, 900), "2031-03-14", "Mar 14, 2031"),
- wizard("narrow", List.of(420, 800), "2032-04-15", "Apr 15, 2032")));
+ wizard("wide", List.of(1280, 900), "2031-03-14"),
+ wizard("narrow", List.of(420, 800), "2032-04-15")));
}
/** The order this places is left in the throwaway test server's store; nothing else reads it. */
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTerminal_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTerminal_BrowserTest.java
index e1bfd4a77c..75538876cd 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTerminal_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTerminal_BrowserTest.java
@@ -20,7 +20,6 @@ import static org.apache.juneau.petstore.console.browser.PetstoreBrowser.*;
import static org.apache.juneau.test.bct.BctAssertions.*;
import static org.junit.jupiter.api.Assertions.*;
-import java.net.*;
import java.net.http.*;
import java.util.*;
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTestServer.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTestServer.java
index dc61f151f6..703fe984c9 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTestServer.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTestServer.java
@@ -35,7 +35,6 @@ import org.apache.juneau.rest.server.filter.*;
import org.apache.juneau.rest.server.servlet.*;
import jakarta.servlet.*;
-import jakarta.servlet.http.*;
/**
* The browser tests' server: the {@code /console} tree, the {@code /petstore} API and the {@code /petstore-ui}
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTreemap_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTreemap_BrowserTest.java
index 6913a2a359..0b1be50c03 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTreemap_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTreemap_BrowserTest.java
@@ -222,7 +222,7 @@ class PetstoreTreemap_BrowserTest extends TestBase {
assertEquals(List.of(), query(c, "writes"));
}
- @Test void a03_submitEdit_putWithCsrf_dialogCloses_treemapRedrawsWithNewSpecies() throws Exception {
+ @Test void a03_submitEdit_putWithCsrf_dialogCloses_treemapRedrawsWithNewSpecies() {
assertSaved("save", moveTo);
}
@@ -231,7 +231,7 @@ class PetstoreTreemap_BrowserTest extends TestBase {
assertEquals(target.getString("species"), new JsonMap(get("/petstore/pets/" + target.getLong("id"))).getString("species"));
}
- private void assertSaved(String name, String species) throws Exception {
+ private void assertSaved(String name, String species) {
var c = assertClean(report, name);
@SuppressWarnings("unchecked") // writes is a JSON array of {url, method, status, csrf, body}.
var w = (List<Map<String,Object>>)query(c, "writes");
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTwins_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTwins_BrowserTest.java
index 20e8bb02e8..4cab88fc9f 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTwins_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTwins_BrowserTest.java
@@ -17,7 +17,6 @@
package org.apache.juneau.petstore.console.browser;
import static org.apache.juneau.petstore.console.browser.PetstoreBrowser.*;
-import static org.apache.juneau.test.bct.BctAssertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTypedConfirm_BrowserTest.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTypedConfirm_BrowserTest.java
index 56c67ed052..6c5e95b8ab 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTypedConfirm_BrowserTest.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/browser/PetstoreTypedConfirm_BrowserTest.java
@@ -80,7 +80,6 @@ class PetstoreTypedConfirm_BrowserTest extends TestBase {
private static final String RES_FALSE = "window.__res === false";
private static Map<String,Map<String,Object>> report;
- private static Map<String,Object> orders;
@BeforeAll
static void probe() throws Exception {
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/DashboardRest_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/DashboardRest_Test.java
index e087f0f69b..73ce552773 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/DashboardRest_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/DashboardRest_Test.java
@@ -85,17 +85,24 @@ class DashboardRest_Test extends TestBase {
//-----------------------------------------------------------------------------------------------------------------
@Test void b01_oneRowPerUtcDay() throws Exception {
- assertString("day,reason,orders\n"
- + "2026-10-01T00:00:00Z,wrong-item,15\n"
- + "2026-10-02T00:00:00Z,late,22\n"
- + "2026-10-03T00:00:00Z,lost,29\n",
+ assertString("""
+ day,reason,orders
+ 2026-10-01T00:00:00Z,wrong-item,15
+ 2026-10-02T00:00:00Z,late,22
+ 2026-10-03T00:00:00Z,lost,29
+ """,
csv("ok", "?start=2026-10-01T00:00:00Z&end=2026-10-04T00:00:00Z"));
}
@Test void b02_filters() throws Exception {
var week = "?start=2026-10-01T00:00:00Z&end=2026-10-08T00:00:00Z";
- assertString("day,reason,orders\n"
- + "2026-10-02T00:00:00Z,late,22\n2026-10-03T00:00:00Z,lost,29\n2026-10-06T00:00:00Z,late,27\n2026-10-07T00:00:00Z,lost,11\n",
+ assertString("""
+ day,reason,orders
+ 2026-10-02T00:00:00Z,late,22
+ 2026-10-03T00:00:00Z,lost,29
+ 2026-10-06T00:00:00Z,late,27
+ 2026-10-07T00:00:00Z,lost,11
+ """,
csv("ok", week + "&reasons=late&reasons=lost"));
assertString("day,reason,orders\n2026-10-03T00:00:00Z,lost,29\n2026-10-07T00:00:00Z,lost,11\n", csv("ok", week + "&q=OS"));
assertString("day,reason,orders\n2026-10-02T00:00:00Z,late,22\n2026-10-06T00:00:00Z,late,27\n", csv("ok", week + "&lateOnly=true"));
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType_Test.java
index 0614aba0ca..c9cadc9713 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/InventoryGaugeCardType_Test.java
@@ -35,7 +35,8 @@ class InventoryGaugeCardType_Test extends TestBase {
}
private static String rejected(String body) {
- return assertThrows(IllegalArgumentException.class, () -> H.toFragment(gauge(body))).getMessage();
+ var source = gauge(body);
+ return assertThrows(IllegalArgumentException.class, () -> H.toFragment(source)).getMessage();
}
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/flavors/FlavorsRest_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/flavors/FlavorsRest_Test.java
index 9567efab02..d057130f69 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/flavors/FlavorsRest_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/dev/flavors/FlavorsRest_Test.java
@@ -19,7 +19,6 @@ package org.apache.juneau.petstore.console.dev.flavors;
import static org.apache.juneau.petstore.console.PetstoreConsoleFixture.*;
import static org.apache.juneau.rest.server.console.test.PageContractAssert.*;
import static org.apache.juneau.test.bct.BctAssertions.*;
-import static org.junit.jupiter.api.Assertions.*;
import java.util.*;
import java.util.regex.*;
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/ops/GroomRuns_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/ops/GroomRuns_Test.java
index dcbef433a8..c49b642d96 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/ops/GroomRuns_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/ops/GroomRuns_Test.java
@@ -96,6 +96,9 @@ class GroomRuns_Test extends TestBase {
}
}
+ @SuppressWarnings({
+ "resource" // The run owns its terminal sources; the enclosing GroomRuns closes them.
+ })
@Test void a05_sourcesAreLookedUpByRunId() throws Exception {
try (var g = new GroomRuns(1)) {
var r = await(g.start("Rex", false, null));
@@ -108,6 +111,9 @@ class GroomRuns_Test extends TestBase {
}
}
+ @SuppressWarnings({
+ "resource" // The run owns its terminal sources; the enclosing GroomRuns closes them.
+ })
@Test void a06_fileSourceTailsTheTranscript() throws Exception {
try (var g = new GroomRuns(1)) {
var r = await(g.start("Rex", false, null));
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/pets/PetsRest_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/pets/PetsRest_Test.java
index 9b67c083f4..5bbd33791d 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/pets/PetsRest_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/console/pets/PetsRest_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.petstore.console.pets;
-import static org.apache.juneau.petstore.console.PetstoreConsoleFixture.*;
import static org.apache.juneau.test.bct.BctAssertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/marshall/PetPhotoParser_Test.java b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/marshall/PetPhotoParser_Test.java
index 934a025d59..20e9763f3d 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/marshall/PetPhotoParser_Test.java
+++ b/juneau-petstore/juneau-petstore-core/src/test/java/org/apache/juneau/petstore/marshall/PetPhotoParser_Test.java
@@ -62,7 +62,8 @@ class PetPhotoParser_Test extends TestBase {
}
@Test void a04_nonImageInputThrowsParseException() {
- assertThrows(ParseException.class, () -> parser.read("not an image".getBytes(StandardCharsets.UTF_8), BufferedImage.class));
+ var input = "not an image".getBytes(StandardCharsets.UTF_8);
+ assertThrows(ParseException.class, () -> parser.read(input, BufferedImage.class));
}
@Test void a05_corruptJpegThrowsParseException() throws Exception {
diff --git a/juneau-petstore/juneau-petstore-core/src/test/js/petstore-browser.cjs b/juneau-petstore/juneau-petstore-core/src/test/js/petstore-browser.cjs
index 80217fa8cc..bd4a79fcc5 100644
--- a/juneau-petstore/juneau-petstore-core/src/test/js/petstore-browser.cjs
+++ b/juneau-petstore/juneau-petstore-core/src/test/js/petstore-browser.cjs
@@ -106,7 +106,7 @@ async function runCase(browser, input, c) {
return r;
}
-async function act(page, input, c, a, r) {
+async function act(page, input, c, a, r) { // NOSONAR javascript:S3776 - one flat dispatch over the action kinds
if (a.click) return page.click(a.click);
if (a.fill) return page.fill(a.fill[0], a.fill[1]);
if (a.press) return page.press(a.press[0], a.press[1]);
diff --git a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
index f239b9d4fa..8e0cfef3d7 100644
--- a/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
+++ b/juneau-petstore/juneau-petstore-jetty/src/test/java/org/apache/juneau/petstore/jetty/PetstoreJetty_Test.java
@@ -55,7 +55,8 @@ import jakarta.servlet.DispatcherType;
@JettyMicroserviceTest
@SuppressWarnings({
"java:S2925", // warmUpServer() readiness loop needs a back-off between retries; without it a ConnectException would busy-spin. No event/latch to await and Awaitility isn't on the test classpath.
- "java:S8692" // warmUpServer() polls a real HTTP server against a genuine wall-clock deadline; a fixed clock would break the retry loop.
+ "java:S8692", // warmUpServer() polls a real HTTP server against a genuine wall-clock deadline; a fixed clock would break the retry loop.
+ "resource" // The microservice bean store is owned by the fixture, which closes it.
})
class PetstoreJetty_Test extends TestBase {
@@ -84,8 +85,7 @@ class PetstoreJetty_Test extends TestBase {
* exceed the tight 10s per-request timeout the test methods use. Absorbing that cold-start here (with a
* generous budget + retry) removes the startup race from {@code a01} while keeping the per-test timeouts tight.
*/
- @BeforeAll
- static void warmUpServer() throws Exception {
+ private static void warmUpServer() throws Exception {
var deadline = Instant.now().plusSeconds(30);
Exception last = null;
while (Instant.now().isBefore(deadline)) {
@@ -114,9 +114,8 @@ class PetstoreJetty_Test extends TestBase {
* The boundary filters sit in front of the root servlet by path, so they cover the replacement exactly as they cover
* the original. The {@code GET} answers {@code 405} and does not exit.
*/
- @BeforeAll
- static void mountTestShutdown() throws Exception {
- get("/", "text/html"); // Initializes the root servlet, whichever @BeforeAll runs first.
+ private static void mountTestShutdown() throws Exception {
+ get("/", "text/html"); // Initializes the root servlet before the shutdown resource is mounted.
RootResources root = null;
for (var h : fixture.getJettyServerComponent().getServletContextHandler().getServletHandler().getServlets())
if (h.getServlet() instanceof RootResources r)
@@ -130,6 +129,13 @@ class PetstoreJetty_Test extends TestBase {
assertEquals(405, get("/shutdown", "application/json").statusCode());
}
+ /** Warms the server up, then mounts the test shutdown resource; the order is fixed. */
+ @BeforeAll
+ static void setUpServer() throws Exception {
+ warmUpServer();
+ mountTestShutdown();
+ }
+
private static HttpResponse<String> get(String path, String accept) throws Exception {
var req = HttpRequest.newBuilder()
.uri(URI.create(fixture.getRootUrl() + path))
@@ -356,7 +362,7 @@ class PetstoreJetty_Test extends TestBase {
@Test void g01_consolePageCarriesTheCsrfToken() throws Exception {
var resp = get("/console/store", "text/html");
assertEquals(200, resp.statusCode(), "body: " + resp.body());
- assertTrue(resp.body().matches("(?s).*<body[^>]*\\sdata-juneau-csrf=\"[0-9a-f]{64}\".*"), "no data-juneau-csrf on <body>");
+ assertTrue(Pattern.compile("<body(?:\\s++[^>\\s]++)*\\s++data-juneau-csrf=\"[0-9a-f]{64}\"").matcher(resp.body()).find(), "no data-juneau-csrf on <body>");
}
@Test void g02_consoleWriteWithoutTheTokenIsRefused() throws Exception {
@@ -473,7 +479,7 @@ class PetstoreJetty_Test extends TestBase {
assertNull(boundaryReason(post), "status " + post.statusCode());
}
- @Test void g09_apiBoundaryIsMappedForRequestOnly() throws Exception {
+ @Test void g09_apiBoundaryIsMappedForRequestOnly() {
var handler = fixture.getJettyServerComponent().getServletContextHandler().getServletHandler();
var mappings = handler.getFilterMappings();
var api = -1;
@@ -597,13 +603,12 @@ class PetstoreJetty_Test extends TestBase {
// Sends a GET with a Host header the HTTP client would not let us set, and returns "<status> <boundary reason>".
private static String rawGet(String path, String host) throws Exception {
var root = fixture.getRootUrl();
- try (var s = new Socket(root.getHost(), root.getPort())) {
+ try (var s = new Socket(root.getHost(), root.getPort()); var out = s.getOutputStream();
+ var in = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.US_ASCII))) {
s.setSoTimeout(30_000);
- var out = s.getOutputStream();
out.write(("GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\nAccept: text/plain\r\nConnection: close\r\n\r\n")
.getBytes(StandardCharsets.US_ASCII));
out.flush();
- var in = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.US_ASCII));
var status = in.readLine().split(" ")[1];
String reason = null;
for (var line = in.readLine(); line != null && ! line.isEmpty(); line = in.readLine())
@@ -657,7 +662,7 @@ class PetstoreJetty_Test extends TestBase {
}
}
- @Test void g23_adminBoundaryIsItsOwnRequestOnlyFilter() throws Exception {
+ @Test void g23_adminBoundaryIsItsOwnRequestOnlyFilter() {
var handler = fixture.getJettyServerComponent().getServletContextHandler().getServletHandler();
var mappings = handler.getFilterMappings();
var api = -1;
diff --git a/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
index 183bc2c605..b95a4e1ded 100644
--- a/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
+++ b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
@@ -362,7 +362,7 @@ class PetstoreSpringboot_Test {
@Test void h01_consolePageCarriesTheCsrfToken() throws Exception {
var resp = get("/console/store", "text/html");
assertEquals(200, resp.statusCode(), "body: " + resp.body());
- assertTrue(resp.body().matches("(?s).*<body[^>]*\\sdata-juneau-csrf=\"[0-9a-f]{64}\".*"), "no data-juneau-csrf on <body>");
+ assertTrue(Pattern.compile("<body(?:\\s++[^>\\s]++)*\\s++data-juneau-csrf=\"[0-9a-f]{64}\"").matcher(resp.body()).find(), "no data-juneau-csrf on <body>");
}
@Test void h02_consoleWriteWithoutTheTokenIsRefused() throws Exception {
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/ApacheHc45TransportBuilder.java b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/ApacheHc45TransportBuilder.java
index ba2abf20ac..8234a6328f 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/ApacheHc45TransportBuilder.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/ApacheHc45TransportBuilder.java
@@ -71,6 +71,9 @@ public final class ApacheHc45TransportBuilder {
* @return This object.
* @throws IllegalArgumentException If the client is an {@link AbstractHttpClient}.
*/
+ @SuppressWarnings({
+ "deprecation" // AbstractHttpClient is referenced only to refuse the legacy client type; there is no replacement check.
+ })
public ApacheHc45TransportBuilder httpClient(CloseableHttpClient value) {
if (reqnn("value", value) instanceof AbstractHttpClient)
throw iaex("A legacy AbstractHttpClient (%s) is not supported: it cannot apply the redirect credential guard. Build the client with HttpClients instead.", value.getClass().getName());
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/Hc45RedirectCredentialGuard.java b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/Hc45RedirectCredentialGuard.java
index 60fc392e5e..49c8b5a728 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/Hc45RedirectCredentialGuard.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/main/java/org/apache/juneau/rest/client/apachehttpclient45/Hc45RedirectCredentialGuard.java
@@ -16,8 +16,6 @@
*/
package org.apache.juneau.rest.client.apachehttpclient45;
-import static org.apache.juneau.commons.utils.Shorts.*;
-
import java.util.*;
import org.apache.http.*;
@@ -139,6 +137,9 @@ final class Hc45RedirectCredentialGuard implements HttpRequestInterceptor {
private boolean protocolPass;
@Override /* HttpCoreContext */
+ @SuppressWarnings({
+ "java:S3776" // Linear attribute-observation state machine; splitting it would scatter the pass tracking.
+ })
public void setAttribute(String id, Object obj) {
super.setAttribute(id, obj);
if (HttpCoreContext.HTTP_TARGET_HOST.equals(id))
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_CallerClientRedirectCredentials_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_CallerClientRedirectCredentials_Test.java
index c13a6939f8..5875e4de40 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_CallerClientRedirectCredentials_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_CallerClientRedirectCredentials_Test.java
@@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.*;
import java.io.*;
import java.net.*;
import java.nio.charset.*;
-import java.util.*;
import java.util.concurrent.atomic.*;
import org.apache.http.*;
@@ -316,7 +315,9 @@ class ApacheHc45Transport_CallerClientRedirectCredentials_Test {
@SuppressWarnings("deprecation") // The legacy AbstractHttpClient family is exactly what is refused.
void e01_legacyDefaultHttpClient_isRefused() {
// Reproduced before the refusal: a legacy client never re-sets the request before the wire, so the store cookie followed a cross-origin redirect.
- var ex = assertThrows(IllegalArgumentException.class, () -> ApacheHc45Transport.builder().httpClient(new org.apache.http.impl.client.DefaultHttpClient()));
+ var builder = ApacheHc45Transport.builder();
+ var legacy = new org.apache.http.impl.client.DefaultHttpClient();
+ var ex = assertThrows(IllegalArgumentException.class, () -> builder.httpClient(legacy));
assertTrue(ex.getMessage().contains("AbstractHttpClient"), ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_SsrfGuard_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_SsrfGuard_Test.java
index 63877603b1..cc53388866 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_SsrfGuard_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-45/src/test/java/org/apache/juneau/rest/client/ApacheHc45Transport_SsrfGuard_Test.java
@@ -46,7 +46,7 @@ class ApacheHc45Transport_SsrfGuard_Test {
server.createContext("/hello", exchange -> {
var body = "hi".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
});
server.start();
@@ -148,9 +148,9 @@ class ApacheHc45Transport_SsrfGuard_Test {
}
private static void assertPlainOk(ApacheHc45Transport transport) throws Exception {
- try (var response = transport.execute(plain())) {
+ try (var response = transport.execute(plain()); var in = response.getBody()) {
assertEquals(200, response.getStatusCode());
- assertEquals("hi", new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8));
+ assertEquals("hi", new String(in.readAllBytes(), StandardCharsets.UTF_8));
}
}
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_BuiltClientRedirectCredentials_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_BuiltClientRedirectCredentials_Test.java
index d7366ad9dc..7ddea81d1f 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_BuiltClientRedirectCredentials_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_BuiltClientRedirectCredentials_Test.java
@@ -27,7 +27,6 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import org.apache.hc.client5.http.*;
-import org.apache.hc.client5.http.protocol.*;
import org.apache.juneau.http.entity.*;
import org.apache.juneau.rest.client.apachehttpclient50.*;
import org.junit.jupiter.api.*;
@@ -40,6 +39,7 @@ import com.sun.net.httpserver.*;
* HttpClient's own redirect handling (method rewrite, redirect cap, circular-redirect check) is unchanged.
*/
@SuppressWarnings({
+ "java:S3415", // Expected value is already first; Sonar mistakes the upper-case constant or field for the expected value
"resource" // Transport/client instances are short-lived test fixtures.
})
// SEPARATE_THREAD: a socket read blocked on a non-responding peer ignores interrupts, so SAME_THREAD would still hang.
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_CallerClientRedirectCredentials_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_CallerClientRedirectCredentials_Test.java
index 0f64496f2c..62b75471af 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_CallerClientRedirectCredentials_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_CallerClientRedirectCredentials_Test.java
@@ -46,6 +46,7 @@ import com.sun.net.httpserver.*;
* credential headers from the cross-origin hop.
*/
@SuppressWarnings({
+ "java:S3415", // Expected value is already first; Sonar mistakes the upper-case constant or field for the expected value
"resource" // Transport/client instances are short-lived test fixtures.
})
// SEPARATE_THREAD: a socket read blocked on a non-responding peer ignores interrupts, so SAME_THREAD would still hang.
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_Edge_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_Edge_Test.java
index b13498274c..5940741fab 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_Edge_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_Edge_Test.java
@@ -65,10 +65,14 @@ class ApacheHc5Transport_Edge_Test {
}
@Override /* ModalCloseable */
- public void close(CloseMode closeMode) {}
+ public void close(CloseMode closeMode) {
+ // no-op by design: test stub
+ }
@Override /* Closeable */
- public void close() {}
+ public void close() {
+ // no-op by design: test stub
+ }
}
/** Same stub, but {@link Configurable} with a configurable (possibly null) default config. */
@@ -118,10 +122,14 @@ class ApacheHc5Transport_Edge_Test {
}
@Override /* HttpEntity */
- public void writeTo(OutputStream out) {}
+ public void writeTo(OutputStream out) {
+ // no-op by design: test stub
+ }
@Override /* Closeable */
- public void close() {}
+ public void close() {
+ // no-op by design: test stub
+ }
});
}
diff --git a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_SsrfGuard_Test.java b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_SsrfGuard_Test.java
index 5f5f84faef..986347a533 100644
--- a/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_SsrfGuard_Test.java
+++ b/juneau-rest/juneau-rest-client-apache-httpclient-50/src/test/java/org/apache/juneau/rest/client/ApacheHc5Transport_SsrfGuard_Test.java
@@ -47,7 +47,7 @@ class ApacheHc5Transport_SsrfGuard_Test {
server.createContext("/hello", exchange -> {
var body = "hi".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
});
server.start();
@@ -113,6 +113,9 @@ class ApacheHc5Transport_SsrfGuard_Test {
}
@Test
+ @SuppressWarnings({
+ "resource" // the caller-supplied client is owned by the transport, which the try-with-resources closes.
+ })
void b02_supportsUrlPolicy_callerSuppliedClient_false() throws Exception {
try (var transport = ApacheHc5Transport.builder().httpClient(HttpClients.createDefault()).build()) {
assertFalse(transport.supportsUrlPolicy(), "a caller-supplied client cannot be given pin-on-connect");
@@ -167,9 +170,9 @@ class ApacheHc5Transport_SsrfGuard_Test {
}
private static void assertPlainOk(ApacheHc5Transport transport) throws Exception {
- try (var response = transport.execute(plain())) {
+ try (var response = transport.execute(plain()); var in = response.getBody()) {
assertEquals(200, response.getStatusCode());
- assertEquals("hi", new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8));
+ assertEquals("hi", new String(in.readAllBytes(), StandardCharsets.UTF_8));
}
}
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/HttpClientBuilderSettings.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/HttpClientBuilderSettings.java
index 008ffdc92d..8916649588 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/HttpClientBuilderSettings.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/HttpClientBuilderSettings.java
@@ -52,6 +52,10 @@ import org.apache.http.protocol.*;
* @param connTimeToLiveTimeUnit The time unit of {@code connTimeToLive}.
* @param systemProperties Whether {@link HttpClientBuilder#useSystemProperties()} was called.
*/
+@SuppressWarnings({
+ "java:S1192", // The field name repeats where each HttpClientBuilder field is read.
+ "java:S3011" // The HttpClientBuilder fields are read reflectively because the builder exposes no getters for them.
+})
record HttpClientBuilderSettings(
SSLContext sslContext,
LayeredConnectionSocketFactory sslSocketFactory,
@@ -182,6 +186,9 @@ record HttpClientBuilderSettings(
* @return The interceptors (empty if none were added).
* @throws IllegalStateException If the builder's fields cannot be read (see {@link #isReadable()}).
*/
+ @SuppressWarnings({
+ "java:S1452" // Package-private helper; interceptors are of mixed types
+ })
static List<?> lastRequestInterceptors(HttpClientBuilder b) {
List<?> interceptors = get(requireReadable(b), "requestLast");
return interceptors == null ? List.of() : interceptors;
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/ResponseContent.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/ResponseContent.java
index b3fdf04b73..16bdb84a80 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/ResponseContent.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/ResponseContent.java
@@ -32,6 +32,7 @@ import org.apache.http.*;
import org.apache.http.conn.*;
import org.apache.juneau.commons.conversion.*;
import org.apache.juneau.commons.http.*;
+import org.apache.juneau.commons.reflect.ConstructorInfo;
import org.apache.juneau.commons.reflect.ExecutableException;
import org.apache.juneau.commons.utils.*;
import org.apache.juneau.http.classic.entity.*;
@@ -262,15 +263,8 @@ public class ResponseContent implements HttpEntity {
type = (ClassMeta<T>)getClassMeta(StreamResource.class);
var responseCtor = type.getPublicConstructor(x -> x.hasParameterTypes(HttpResponse.class));
- if (responseCtor.isPresent()) {
- try {
- return responseCtor.get().newInstance(response);
- } catch (ExecutableException e) {
- // The (HttpResponse) constructor rejected the response (e.g. the status code does not match the class).
- response.close();
- throw new RestCallException(response, e.getCause() == null ? e : e.getCause(), "Could not construct %s from response.", type.inner().getName());
- }
- }
+ if (responseCtor.isPresent())
+ return construct(responseCtor.get(), type);
var ct = firstNonEmpty(response.getHeader(HEADER_ContentType).orElse(CONTENT_TYPE_TEXT_PLAIN));
@@ -282,30 +276,8 @@ public class ResponseContent implements HttpEntity {
if ((parser == null || (mt.toString().contains(CONTENT_TYPE_TEXT_PLAIN) && ! parser.canHandle(ct))) && type.hasStringMutater())
return BasicConverter.INSTANCE.to(asString(), type.inner());
- if (nn(parser)) {
- try (Closeable in = parser.isReaderParser() ? asReader() : asInputStream()) {
-
- // @formatter:off
- T t = parser
- .createSession()
- .properties(JsonMap.create().inner(request.getSessionProperties()))
- .locale(response.getLocale())
- .mediaType(mt)
- .schema(schema)
- .build()
- .read(in, type);
- // @formatter:on
-
- // Some HTTP responses have no body, so try to create these beans if they've got no-arg constructors.
- if (t == null && ! type.is(String.class)) {
- var result2 = type.getPublicConstructor(cons -> cons.getParameterCount() == 0).map(c -> safe(() -> (T)c.newInstance()));
- if (result2.isPresent())
- return result2.get();
- }
-
- return t;
- }
- }
+ if (nn(parser))
+ return parse(type, mt);
if (type.hasReaderMutater())
return BasicConverter.INSTANCE.to(asReader(), type.inner());
@@ -326,6 +298,50 @@ public class ResponseContent implements HttpEntity {
}
}
+ /**
+ * Constructs the target type from the response through its {@code (HttpResponse)} constructor.
+ */
+ private <T> T construct(ConstructorInfo ctor, ClassMeta<T> type) throws RestCallException {
+ try {
+ return ctor.newInstance(response);
+ } catch (ExecutableException e) {
+ // The (HttpResponse) constructor rejected the response (e.g. the status code does not match the class).
+ response.close();
+ throw new RestCallException(response, e.getCause() == null ? e : e.getCause(), "Could not construct %s from response.", type.inner().getName());
+ }
+ }
+
+ /**
+ * Parses the response body with the matched parser.
+ */
+ @SuppressWarnings({
+ "unchecked" // Type erasure requires unchecked casts in content parsing
+ })
+ private <T> T parse(ClassMeta<T> type, MediaType mt) throws ParseException, IOException {
+ try (Closeable in = parser.isReaderParser() ? asReader() : asInputStream()) {
+
+ // @formatter:off
+ T t = parser
+ .createSession()
+ .properties(JsonMap.create().inner(request.getSessionProperties()))
+ .locale(response.getLocale())
+ .mediaType(mt)
+ .schema(schema)
+ .build()
+ .read(in, type);
+ // @formatter:on
+
+ // Some HTTP responses have no body, so try to create these beans if they've got no-arg constructors.
+ if (t == null && ! type.is(String.class)) {
+ var result2 = type.getPublicConstructor(cons -> cons.getParameterCount() == 0).map(c -> safe(() -> (T)c.newInstance()));
+ if (result2.isPresent())
+ return result2.get();
+ }
+
+ return t;
+ }
+ }
+
/**
* Resolves a cursor return type ({@link RecordReader} / {@link TokenReader} or any subtype)
* by negotiating the response Content-Type to a parser and calling its
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestClient.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestClient.java
index 24e20823fa..3018f9d227 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestClient.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestClient.java
@@ -1879,8 +1879,7 @@ public class RestClient extends MarshallingContextable implements HttpClient, Cl
*/
public SELF allowAddressRanges(String...value) {
if (nn(value))
- for (var v : value)
- allowedAddressRanges.add(v);
+ Collections.addAll(allowedAddressRanges, value);
return self();
}
@@ -6104,7 +6103,7 @@ public class RestClient extends MarshallingContextable implements HttpClient, Cl
private static String[] splitSystemProperty(String name) {
var v = System.getProperty(name);
- return ib(v) ? null : v.split(" *, *");
+ return ib(v) ? null : v.split(" *+, *+");
}
// The pool settings, applied as Apache HttpClientBuilder applies them to its own connection manager. The
@@ -6114,8 +6113,10 @@ public class RestClient extends MarshallingContextable implements HttpClient, Cl
private PoolSettings poolSettings(HttpClientBuilderSettings s) {
var systemMax = (systemProperties || s.systemProperties()) && "true".equalsIgnoreCase(System.getProperty("http.keepAlive", "true"))
? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
- var maxTotal = maxConnTotal > 0 ? maxConnTotal : s.maxConnTotal() > 0 ? s.maxConnTotal() : 2 * systemMax;
- var maxPerRoute = maxConnPerRoute > 0 ? maxConnPerRoute : s.maxConnPerRoute() > 0 ? s.maxConnPerRoute() : systemMax;
+ var settingsTotal = s.maxConnTotal() > 0 ? s.maxConnTotal() : 2 * systemMax;
+ var settingsPerRoute = s.maxConnPerRoute() > 0 ? s.maxConnPerRoute() : systemMax;
+ var maxTotal = maxConnTotal > 0 ? maxConnTotal : settingsTotal;
+ var maxPerRoute = maxConnPerRoute > 0 ? maxConnPerRoute : settingsPerRoute;
var ownTtl = connTimeToLive > 0;
var ttl = ownTtl ? connTimeToLive : s.connTimeToLive();
var ttlUnit = ownTtl ? connTimeToLiveTimeUnit : s.connTimeToLiveTimeUnit();
@@ -6313,9 +6314,9 @@ public class RestClient extends MarshallingContextable implements HttpClient, Cl
// connection manager down, so a reused builder must not hand an earlier client's to the next one.
var cm = nn(connectionManager) ? connectionManager : createConnectionManager();
// Only a connection manager this builder created can be given a pinned twin; for any other one, the client
- // reports the SSRF guard as unsupported and refuses guarded @Remote calls. The twin is built from the same
- // socket factories and pool settings as cm (defaultRegistry and defaultPoolSettings), so it is the same kind;
- // settings an override applied to the cm instance afterwards reach it before each guarded lease.
+ // reports the SSRF guard as unsupported and refuses guarded remote calls. The twin is built from the same
+ // socket factories and pool settings as the connection manager, so it is the same kind; settings an
+ // override applied to that instance afterwards reach it before each guarded lease.
ssrfGuard = nn(cm) && cm == defaultConnectionManager ? new SsrfGuardConnectionManager(cm, newConnectionManager(defaultRegistry, pinningResolver(), defaultPoolSettings)) : null;
ownsConnectionManager = nn(ssrfGuard) && connectionManager == null && ! overridesCreateConnectionManager(getClass());
if (nn(ssrfGuard))
@@ -6497,7 +6498,7 @@ public class RestClient extends MarshallingContextable implements HttpClient, Cl
private final Logger logger;
private final Map<Class<?>,HttpPartParser> partParsers = new ConcurrentHashMap<>();
private final Map<Class<?>,HttpPartSerializer> partSerializers = new ConcurrentHashMap<>();
- private final Pattern absUrlPattern = Pattern.compile("^\\w+\\:\\/\\/.*");
+ private final Pattern absUrlPattern = Pattern.compile("^\\w++://.*");
private final PrintStream console;
private final RestCallHandler callHandler;
private StackTraceElement[] closedStack;
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestRequest.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestRequest.java
index 6cf4561357..23b3da5060 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestRequest.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/RestRequest.java
@@ -2174,16 +2174,8 @@ public class RestRequest extends MarshallingSession implements HttpUriRequest, C
var ci = ClassInfo.of(t);
Throwable thrownInstance = null;
c = ci.getPublicConstructor(x -> x.hasParameterTypes(HttpResponse.class)).orElse(null);
- if (nn(c)) {
- try {
- thrownInstance = c.<Throwable>newInstance(response);
- } catch (ExecutableException e) {
- // Only a status-code rejection (IllegalArgumentException from the Xxx(HttpResponse) status check) falls through to the remaining constructors; anything else propagates unchanged.
- if (! (e.getCause() instanceof IllegalArgumentException))
- throw e;
- thrownInstance = null;
- }
- }
+ if (nn(c))
+ thrownInstance = newThrownFromResponse(c);
if (thrownInstance == null) {
c = ci.getPublicConstructor(x -> x.hasParameterTypes(String.class)).orElse(null);
if (nn(c)) {
@@ -2325,6 +2317,23 @@ public class RestRequest extends MarshallingSession implements HttpUriRequest, C
return statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307 || statusCode == 308;
}
+ /**
+ * Constructs the server-thrown exception through its {@code (HttpResponse)} constructor.
+ *
+ * @param c The constructor.
+ * @return The instance, or <jk>null</jk> if the constructor rejected the response's status code.
+ */
+ private Throwable newThrownFromResponse(ConstructorInfo c) {
+ try {
+ return c.<Throwable>newInstance(response);
+ } catch (ExecutableException e) {
+ // Only a status-code rejection (IllegalArgumentException from the Xxx(HttpResponse) status check) falls through to the remaining constructors; anything else propagates unchanged.
+ if (! (e.getCause() instanceof IllegalArgumentException))
+ throw e;
+ return null;
+ }
+ }
+
/**
* Builds the request for the next hop of a policy-covered redirect chain, following conventional {@code 3xx}
* semantics: {@code 301}/{@code 302}/{@code 303} rewrite the method to {@code GET} with no body unless the
@@ -3080,9 +3089,6 @@ public class RestRequest extends MarshallingSession implements HttpUriRequest, C
* cursor opened over a temporary buffer, then sending the buffered bytes as the request
* body.
*/
- @SuppressWarnings({
- "rawtypes" // The body consumer's element type depends on the writer kind, so it is invoked through a raw Consumer.
- })
private HttpEntity streamBodyEntity(RecordStreamBody body, Serializer serializer) {
if (serializer == null)
throw iaex("No serializer registered for cursor-streamed request body.");
@@ -3100,12 +3106,7 @@ public class RestRequest extends MarshallingSession implements HttpUriRequest, C
? new OutputStreamWriter(buf, java.nio.charset.StandardCharsets.UTF_8)
: buf;
- try (var w = (writerKind == TokenWriter.class)
- ? ((TokenWritable) serializer).writeTokens(output)
- : ((RecordWritable) serializer).writeRecords(output)) {
- ((Consumer) consumer).accept(w);
- w.flush();
- }
+ writeCursor(serializer, writerKind, consumer, output);
// Use the serializer's primary produces() media type if no explicit Content-Type set.
var ct = serializer.getPrimaryMediaType();
@@ -3115,4 +3116,16 @@ public class RestRequest extends MarshallingSession implements HttpUriRequest, C
throw rex(e, "I/O error streaming request body.");
}
}
+
+ @SuppressWarnings({
+ "rawtypes" // The body consumer's element type depends on the writer kind, so it is invoked through a raw Consumer.
+ })
+ private static void writeCursor(Serializer serializer, Class<?> writerKind, Object consumer, Object output) throws IOException {
+ try (var w = (writerKind == TokenWriter.class)
+ ? ((TokenWritable) serializer).writeTokens(output)
+ : ((RecordWritable) serializer).writeRecords(output)) {
+ ((Consumer) consumer).accept(w);
+ w.flush();
+ }
+ }
}
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardConnectionManager.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardConnectionManager.java
index ce40680d0a..b53ac8c7d2 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardConnectionManager.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardConnectionManager.java
@@ -70,15 +70,15 @@ final class SsrfGuardConnectionManager implements HttpClientConnectionManager {
private final HttpClientConnectionManager ordinary;
private final HttpClientConnectionManager pinned;
- // The lease decision GuardInterceptor hands to the next requestConnection(...) on the same thread: set (to TRUE) for
- // a guarded request, absent otherwise. GuardInterceptor sets or clears it for every request and requestConnection
+ // The lease decision that GuardInterceptor hands to the next requestConnection call on the same thread: set to true
+ // for a guarded request, absent otherwise. GuardInterceptor sets or clears it for every request and requestConnection
// clears it before anything else, so a decision can only be left over when a request interceptor after GuardInterceptor
// throws before the lease; the next lease on that thread is then pinned although its request is not guarded. A
- // leftover can only over-guard (pin an ordinary request), never let a guarded one through unpinned.
+ // leftover can only over-guard by pinning an ordinary request, and never lets a guarded one through unpinned.
private static final ThreadLocal<Boolean> NEXT_LEASE_GUARDED = new ThreadLocal<>();
- // Leased connections of the pinned pool. Connection classes use identity equality, so this is an identity map;
- // weak keys mean a leaked (never released) connection is not kept alive by this map.
+ // Leased connections of the pinned pool. Connection classes use identity equality, so this is an identity map.
+ // Weak keys mean a leaked (never released) connection is not kept alive by this map.
private final Map<HttpClientConnection,Boolean> pinnedLeases = Collections.synchronizedMap(new WeakHashMap<>());
SsrfGuardConnectionManager(HttpClientConnectionManager ordinary, HttpClientConnectionManager pinned) {
@@ -102,6 +102,9 @@ final class SsrfGuardConnectionManager implements HttpClientConnectionManager {
var request = pinned.requestConnection(route, state);
return new ConnectionRequest() {
@Override /* ConnectionRequest */
+ @SuppressWarnings({
+ "resource" // the leased connection is handed to the caller, which releases it through releaseConnection().
+ })
public HttpClientConnection get(long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
var conn = request.get(timeout, timeUnit);
pinnedLeases.put(conn, Boolean.TRUE);
@@ -160,6 +163,9 @@ final class SsrfGuardConnectionManager implements HttpClientConnectionManager {
// not wired, so guarded calls are refused).
private static final Field CONN_MANAGER = connManagerField();
+ @SuppressWarnings({
+ "java:S3011" // The client's connection manager has no accessor, so the field is read reflectively.
+ })
private static Field connManagerField() {
try {
var f = Class.forName("org.apache.http.impl.client.InternalHttpClient").getDeclaredField("connManager");
@@ -220,6 +226,9 @@ final class SsrfGuardConnectionManager implements HttpClientConnectionManager {
// Copies the ordinary pool's settings onto the pinned pool (both are built by the same factory, so they are always
// the same kind). Only changed values are written: each setter takes the pool's lock.
+ @SuppressWarnings({
+ "java:S3776" // One flat run of compare-and-copy steps, one per pool setting.
+ })
private void mirrorSettings(HttpRoute route) {
if (ordinary instanceof PoolingHttpClientConnectionManager o) {
var p = (PoolingHttpClientConnectionManager)pinned;
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardMarker.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardMarker.java
index 13575c73f4..b62367b932 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardMarker.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/SsrfGuardMarker.java
@@ -68,10 +68,15 @@ final class SsrfGuardMarker {
* @throws SsrfGuardConnectionManager.GuardRefusedException If a guarded {@link RestRequest} created the request but
* the context lacks the marker.
*/
+ @SuppressWarnings({
+ "resource" // RestRequest is only inspected here; its lifecycle belongs to the caller.
+ })
static boolean isGuarded(HttpRequest request, HttpContext context) {
if (nn(context) && Boolean.TRUE.equals(context.getAttribute(ATTRIBUTE)))
return true;
- var r = nn(request) ? request : nn(context) ? (HttpRequest)context.getAttribute(HttpCoreContext.HTTP_REQUEST) : null;
+ var r = request;
+ if (r == null && nn(context))
+ r = (HttpRequest)context.getAttribute(HttpCoreContext.HTTP_REQUEST);
while (r instanceof HttpRequestWrapper w)
r = w.getOriginal();
if (r instanceof RestRequestCreated c && nn(c.getRestRequest()) && c.getRestRequest().isSsrfGuarded())
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException.java
index 2bbaa595db..007b0ea418 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException.java
@@ -39,7 +39,7 @@ public class RemoteMetadataException extends BasicRuntimeException {
private static final long serialVersionUID = 1L;
private static final String getMessage(Class<?> c, Method m, String msg) {
- var sb = new StringBuilder("Invalid remote definition found on class ").append(c.getName());
+ var sb = new StringBuilder("Invalid remote definition found on class ").append(c == null ? null : c.getName());
if (nn(m))
sb.append(" on method ").append(m.getName());
sb.append(". ").append(msg);
@@ -65,7 +65,7 @@ public class RemoteMetadataException extends BasicRuntimeException {
* @param args Optional {@link String#format(String, Object...) String.format}-style arguments.
*/
public RemoteMetadataException(Method m, String message, Object...args) {
- this((Throwable)null, getMessage(m.getDeclaringClass(), m, message), args);
+ this((Throwable)null, getMessage(m == null ? null : m.getDeclaringClass(), m, message), args);
}
/**
diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteProxyUtils.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteProxyUtils.java
index 019085fac9..474979f045 100644
--- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteProxyUtils.java
+++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/remote/RemoteProxyUtils.java
@@ -151,7 +151,7 @@ public class RemoteProxyUtils {
*
* @param url The URL to validate.
* @param allowPrivateUrls When <jk>true</jk>, the deny-private check is skipped.
- * @param allowedRanges The client's {@link RemoteUrlPolicy.AllowedRanges}, unioned with the {@code RestClient.allowAddressRanges} property.
+ * @param allowedRanges The client's {@link org.apache.juneau.http.remote.RemoteUrlPolicy.AllowedRanges}, unioned with the {@code RestClient.allowAddressRanges} property.
* @return The unchanged URL.
* @throws IllegalArgumentException If {@code url} is absolute and violates the policy.
*/
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_AllowAddressRanges_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_AllowAddressRanges_Test.java
index 05c9fbe80c..d684cb36df 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_AllowAddressRanges_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_AllowAddressRanges_Test.java
@@ -71,9 +71,12 @@ class RestClient_AllowAddressRanges_Test {
// =================================================================================================================
@Test void a01_invalidSpec_failsAtBuild() {
- assertThrows(IllegalArgumentException.class, () -> RestClient.create().allowAddressRanges("10.0.0.0/8").build());
- assertThrows(IllegalArgumentException.class, () -> RestClient.create().allowAddressRanges("not-an-address").build());
- assertThrows(IllegalArgumentException.class, () -> RestClient.create().allowAddressRanges("127.0.0.1").build());
+ var tenSlashEight = RestClient.create().allowAddressRanges("10.0.0.0/8");
+ var notAnAddress = RestClient.create().allowAddressRanges("not-an-address");
+ var bareAddress = RestClient.create().allowAddressRanges("127.0.0.1");
+ assertThrows(IllegalArgumentException.class, tenSlashEight::build);
+ assertThrows(IllegalArgumentException.class, notAnAddress::build);
+ assertThrows(IllegalArgumentException.class, bareAddress::build);
}
@Test void a02_getter_reflectsSettingAndAccumulates() throws Exception {
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_ConnectionManager_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_ConnectionManager_Test.java
index 6c9b333d15..21aad556d1 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_ConnectionManager_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_ConnectionManager_Test.java
@@ -119,19 +119,19 @@ class RestClient_ConnectionManager_Test {
}
private static void hello(HttpExchange exchange) throws IOException {
- exchange.getRequestBody().readAllBytes();
+ try (var in = exchange.getRequestBody()) { in.readAllBytes(); }
var body = "hi".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
}
// Answers with the TLS protocol version the connection negotiated.
private static void protocol(HttpExchange exchange) throws IOException {
- exchange.getRequestBody().readAllBytes();
+ try (var in = exchange.getRequestBody()) { in.readAllBytes(); }
var body = ((HttpsExchange)exchange).getSSLSession().getProtocol().getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
}
@@ -144,7 +144,10 @@ class RestClient_ConnectionManager_Test {
"-validity", "2", "-dname", "CN=localhost", "-ext", "SAN=dns:localhost", "-storetype", "PKCS12",
"-keystore", file.toString(), "-storepass", "changeit", "-keypass", "changeit")
.redirectErrorStream(true).start();
- var out = new String(p.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
+ String out;
+ try (var is = p.getInputStream()) {
+ out = new String(is.readAllBytes(), StandardCharsets.UTF_8);
+ }
assertEquals(0, p.waitFor(), out);
var ks = KeyStore.getInstance("PKCS12");
try (var in = Files.newInputStream(file)) {
@@ -176,26 +179,26 @@ class RestClient_ConnectionManager_Test {
@Test void a01_sslContext_customTrustStore_honoured() throws Exception {
try (var c = RestClient.create().sslContext(trustingContext).build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
}
}
@Test void a02_sslContext_defaultHostnameVerification_stillApplies() throws Exception {
try (var c = RestClient.create().sslContext(trustingContext).build()) {
- var ex = assertThrows(Exception.class, () -> c.get("https://127.0.0.1:" + tlsPort + "/hello").run());
+ var ex = assertThrows(Exception.class, () -> fetch(c, "https://127.0.0.1:" + tlsPort + "/hello"));
assertContains("doesn't match any of the subject alternative names", messages(ex));
}
}
@Test void a03_sslHostnameVerifier_honoured() throws Exception {
try (var c = RestClient.create().sslContext(trustingContext).sslHostnameVerifier(NoopHostnameVerifier.INSTANCE).build()) {
- assertEquals("hi", c.get("https://127.0.0.1:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://127.0.0.1:" + tlsPort + "/hello"));
}
}
@Test void a04_sslSocketFactory_honoured() throws Exception {
try (var c = RestClient.create().sslSocketFactory(new SSLConnectionSocketFactory(trustingContext)).build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
}
}
@@ -232,7 +235,9 @@ class RestClient_ConnectionManager_Test {
try (var c = RestClient.create().pooled().maxConnTotal(9).build()) {
var ordinary = (PoolingHttpClientConnectionManager)ordinaryPool(c);
assertEquals(9, ordinary.getMaxTotal());
- assertEquals(new PoolingHttpClientConnectionManager().getDefaultMaxPerRoute(), ordinary.getDefaultMaxPerRoute());
+ try (var expected = new PoolingHttpClientConnectionManager()) {
+ assertEquals(expected.getDefaultMaxPerRoute(), ordinary.getDefaultMaxPerRoute());
+ }
}
}
@@ -248,11 +253,14 @@ class RestClient_ConnectionManager_Test {
assertSame(NoopHostnameVerifier.INSTANCE, field(httpsFactory(ordinaryPool(c)), "hostnameVerifier"));
assertSame(httpsFactory(ordinaryPool(c)), httpsFactory(pinnedPool(c)));
// The default trust store does not trust the self-signed certificate.
- var ex = assertThrows(Exception.class, () -> c.get("https://localhost:" + tlsPort + "/hello").run());
+ var ex = assertThrows(Exception.class, () -> fetch(c, "https://localhost:" + tlsPort + "/hello"));
assertContains("PKIX path building failed", messages(ex));
}
}
+ @SuppressWarnings({
+ "resource" // The pools are owned and closed by the client; the test only inspects them.
+ })
@Test void a11_noPoolSettings_basicManagerKept() throws Exception {
try (var c = RestClient.create().build()) {
assertInstanceOf(BasicHttpClientConnectionManager.class, ordinaryPool(c));
@@ -276,10 +284,13 @@ class RestClient_ConnectionManager_Test {
// The loopback server answers the proxied request itself; the target host is never resolved.
try (var c = RestClient.create().rootUrl("http://target.invalid").proxy(new HttpHost("127.0.0.1", port)).allowPrivateUrls(true).build()) {
assertEquals("hi", c.getRemote(HelloRemote.class).call());
- assertEquals("hi", c.get("http://target.invalid/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "http://target.invalid/hello"));
}
}
+ @SuppressWarnings({
+ "resource" // The router shuts both pools down in the finally block.
+ })
@Test void b03_router_proxiedRoute_guardedLease_refused() {
var ordinary = new PoolingHttpClientConnectionManager();
var pinned = new PoolingHttpClientConnectionManager();
@@ -363,6 +374,9 @@ class RestClient_ConnectionManager_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The caller-supplied manager is shut down in the finally block.
+ })
@Test void d03_builderReused_callerSuppliedConnectionManager_kept() throws Exception {
var cm = new PoolingHttpClientConnectionManager();
var b = RestClient.create().rootUrl(url).connectionManager(cm).connectionManagerShared(true);
@@ -387,6 +401,9 @@ class RestClient_ConnectionManager_Test {
assertShutDown(pinned);
}
+ @SuppressWarnings({
+ "resource" // The subject is closeQuietly() itself, so the client is closed explicitly.
+ })
@Test void d05_connectionManagerShared_defaultManager_shutDownOnCloseQuietly() throws Exception {
var c = RestClient.create().rootUrl(url).pooled().connectionManagerShared(true).build();
assertPlainOk(c);
@@ -396,19 +413,22 @@ class RestClient_ConnectionManager_Test {
assertShutDown(pinnedPool(c));
}
+ @SuppressWarnings({
+ "resource" // The subject is closeQuietly() on a client sharing the manager, which is shut down in the finally block.
+ })
@Test void d06_connectionManagerShared_callerSuppliedManager_leftOpenOnClose() throws Exception {
- var cm = new PoolingHttpClientConnectionManager();
- try {
+ try (var cm = new PoolingHttpClientConnectionManager()) {
try (var c = RestClient.create().rootUrl(url).connectionManager(cm).connectionManagerShared(true).build()) {
assertPlainOk(c);
}
RestClient.create().rootUrl(url).connectionManager(cm).connectionManagerShared(true).build().closeQuietly();
assertOpen(cm);
- } finally {
- cm.shutdown();
}
}
+ @SuppressWarnings({
+ "resource" // The subject is close() itself; the pools are shut down in the finally block.
+ })
@Test void d07_connectionManagerShared_keepHttpClientOpen_defaultManagerLeftOpen() throws Exception {
var c = RestClient.create().rootUrl(url).pooled().connectionManagerShared(true).keepHttpClientOpen().build();
var ordinary = ordinaryPool(c);
@@ -423,6 +443,9 @@ class RestClient_ConnectionManager_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The subject is close() on clients sharing a manager, so the clients are closed explicitly.
+ })
@Test void d08_connectionManagerShared_overriddenCreateConnectionManager_leftOpenOnClose() throws Exception {
var b = new ReusingBuilder().rootUrl(url).pooled().connectionManagerShared(true);
var c1 = b.build();
@@ -448,8 +471,8 @@ class RestClient_ConnectionManager_Test {
@Test void d09_connectionManagerShared_suppliedDefaultManager_leftOpenOnClose() throws Exception {
var b = RestClient.create().rootUrl(url).pooled().connectionManagerShared(true);
var cm = b.createConnectionManager();
- b.connectionManager(cm);
try {
+ b.connectionManager(cm);
try (var c = b.build()) {
assertPlainOk(c);
}
@@ -538,6 +561,9 @@ class RestClient_ConnectionManager_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The caller-supplied manager is owned by the client built from it.
+ })
@Test void e09_basicCallHandlerOfAnotherClient_guardedCall_refused() throws Exception {
try (var other = RestClient.create().connectionManager(new PoolingHttpClientConnectionManager()).build()) {
var b = RestClient.create().rootUrl(url);
@@ -557,6 +583,9 @@ class RestClient_ConnectionManager_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The caller-supplied manager is owned by the client built from it.
+ })
@Test void e11_subclassCreatesRequestBoundToAnotherClient_guardedCall_refused() throws Exception {
try (var other = RestClient.create().connectionManager(new PoolingHttpClientConnectionManager()).build()) {
try (var c = RestClient.create().rootUrl(url).build(OtherClientRequestClient.class)) {
@@ -575,11 +604,17 @@ class RestClient_ConnectionManager_Test {
// Creates its requests on another client, so they go out through that client's HttpClient.
public static class OtherClientRequestClient extends RestClient {
+ @SuppressWarnings({
+ "resource" // A test fixture set and cleared by the test that closes it.
+ })
static volatile RestClient other;
public OtherClientRequestClient(RestClient.Builder<?> builder) {
super(builder);
}
@Override
+ @SuppressWarnings({
+ "resource" // The request is returned to the caller, which owns it.
+ })
protected RestRequest createRequest(URI uri, String method, boolean hasBody) throws RestCallException {
return new RestRequest(other, uri, method, hasBody);
}
@@ -590,6 +625,9 @@ class RestClient_ConnectionManager_Test {
super(builder);
}
@Override
+ @SuppressWarnings({
+ "resource" // The request is returned to the caller, which owns it.
+ })
protected RestRequest createRequest(URI uri, String method, boolean hasBody) throws RestCallException {
return new OtherThreadRequest(this, uri, method, hasBody);
}
@@ -601,6 +639,9 @@ class RestClient_ConnectionManager_Test {
super(client, uri, method, hasBody);
}
@Override
+ @SuppressWarnings({
+ "resource" // The response is returned to the caller, which owns it.
+ })
public RestResponse run() throws RestCallException {
var es = Executors.newSingleThreadExecutor();
try {
@@ -669,7 +710,7 @@ class RestClient_ConnectionManager_Test {
@Test void f01_callerBuilder_sslContext_customTrustStore_honoured() throws Exception {
try (var c = RestClient.create().httpClientBuilder(HttpClientBuilder.create().setSSLContext(trustingContext)).build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
assertSame(httpsFactory(ordinaryPool(c)), httpsFactory(pinnedPool(c)));
}
}
@@ -677,7 +718,7 @@ class RestClient_ConnectionManager_Test {
@Test void f02_callerBuilder_sslHostnameVerifier_honoured() throws Exception {
var b = HttpClientBuilder.create().setSSLContext(trustingContext).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
try (var c = RestClient.create().httpClientBuilder(b).build()) {
- assertEquals("hi", c.get("https://127.0.0.1:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://127.0.0.1:" + tlsPort + "/hello"));
}
}
@@ -711,7 +752,7 @@ class RestClient_ConnectionManager_Test {
}
@Test void f06_callerBuilder_dnsResolver_ordinaryPoolOnly() throws Exception {
- DnsResolver resolver = host -> SystemDefaultDnsResolver.INSTANCE.resolve(host);
+ DnsResolver resolver = SystemDefaultDnsResolver.INSTANCE::resolve;
try (var c = RestClient.create().rootUrl(url).httpClientBuilder(HttpClientBuilder.create().setDnsResolver(resolver)).build()) {
assertSame(resolver, field(field(ordinaryPool(c), "connectionOperator"), "dnsResolver"));
// The pinned pool keeps the pin, so guarded calls are still checked.
@@ -725,7 +766,7 @@ class RestClient_ConnectionManager_Test {
// sslContext(...) was set on the builder created first; the replacement carries a context with the default trust store.
var b = RestClient.create().sslContext(trustingContext).httpClientBuilder(HttpClientBuilder.create().setSSLContext(SSLContexts.createDefault()));
try (var c = b.build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
}
}
@@ -739,7 +780,7 @@ class RestClient_ConnectionManager_Test {
var previous = SSLContext.getDefault();
SSLContext.setDefault(trustingContext);
try (var c = RestClient.create().useSystemProperties().build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
assertSame(httpsFactory(ordinaryPool(c)), httpsFactory(pinnedPool(c)));
} finally {
SSLContext.setDefault(previous);
@@ -749,7 +790,7 @@ class RestClient_ConnectionManager_Test {
@Test void g02_useSystemProperties_httpsProtocols_honoured() throws Exception {
withSystemProperty("https.protocols", "TLSv1.2", () -> {
try (var c = RestClient.create().useSystemProperties().sslContext(trustingContext).build()) {
- assertEquals("TLSv1.2", c.get("https://localhost:" + tlsPort + "/protocol").run().getContent().asString());
+ assertEquals("TLSv1.2", fetch(c, "https://localhost:" + tlsPort + "/protocol"));
for (var pool : pools(c))
assertArrayEquals(new String[]{"TLSv1.2"}, (String[])field(httpsFactory(pool), "supportedProtocols"));
}
@@ -787,6 +828,9 @@ class RestClient_ConnectionManager_Test {
});
}
+ @SuppressWarnings({
+ "resource" // The pools are owned and closed by the client; the test only inspects them.
+ })
@Test void g06_useSystemProperties_keepAliveOff_noPoolLimitsApplied() throws Exception {
withSystemProperty("http.keepAlive", "false", () -> {
try (var c = RestClient.create().useSystemProperties().build()) {
@@ -824,6 +868,9 @@ class RestClient_ConnectionManager_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The pools are owned and closed by the client; the test only inspects them.
+ })
@Test void h03_connectionTimeToLive_pooledInBothPools() throws Exception {
try (var c = RestClient.create().rootUrl(url).connectionTimeToLive(5, TimeUnit.SECONDS).build()) {
for (var pool : pools(c)) {
@@ -847,6 +894,9 @@ class RestClient_ConnectionManager_Test {
// J: connection-manager settings made through this builder carry over a replaced HttpClientBuilder
// =================================================================================================================
+ @SuppressWarnings({
+ "resource" // The pools are owned and closed by the client; the test only inspects them.
+ })
@Test void j01_connectionTimeToLive_carriesOverReplacedBuilder() throws Exception {
var b = RestClient.create().connectionTimeToLive(5, TimeUnit.SECONDS).httpClientBuilder(HttpClientBuilder.create());
try (var c = b.build()) {
@@ -886,7 +936,7 @@ class RestClient_ConnectionManager_Test {
var previous = SSLContext.getDefault();
SSLContext.setDefault(trustingContext);
try (var c = RestClient.create().useSystemProperties().httpClientBuilder(HttpClientBuilder.create()).build()) {
- assertEquals("hi", c.get("https://localhost:" + tlsPort + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, "https://localhost:" + tlsPort + "/hello"));
} finally {
SSLContext.setDefault(previous);
}
@@ -990,10 +1040,11 @@ class RestClient_ConnectionManager_Test {
@Test void k07_guardedRequest_otherThreadWithoutContext_refused() throws Exception {
try (var c = RestClient.create().rootUrl(url).callHandler(OtherThreadCallHandler.class).build()) {
OtherThreadCallHandler.dropContext = true;
- var rc = c.get(url + "/hello");
- rc.ssrfGuard();
- var ex = assertThrows(Exception.class, rc::run);
- assertContains("lacks the SSRF-guard marker", messages(ex));
+ try (var rc = c.get(url + "/hello")) {
+ rc.ssrfGuard();
+ var ex = assertThrows(Exception.class, rc::run);
+ assertContains("lacks the SSRF-guard marker", messages(ex));
+ }
// An ordinary request through the same handler is unaffected.
assertPlainOk(c);
} finally {
@@ -1003,21 +1054,27 @@ class RestClient_ConnectionManager_Test {
@Test void k11_guardedRequest_otherThreadWithContext_pinned() throws Exception {
try (var c = RestClient.create().rootUrl(url).callHandler(OtherThreadCallHandler.class).build()) {
- var rc = c.get(url + "/hello");
- rc.ssrfGuard();
- var ex = assertThrows(Exception.class, rc::run);
- assertContains("No allowed address for host '2130706433'", messages(ex));
+ try (var rc = c.get(url + "/hello")) {
+ rc.ssrfGuard();
+ var ex = assertThrows(Exception.class, rc::run);
+ assertContains("No allowed address for host '2130706433'", messages(ex));
+ }
assertPlainOk(c);
}
}
+ @SuppressWarnings({
+ "resource" // context() returns the request itself, which the try-with-resources closes.
+ })
@Test void k12_guardedRequest_callerContext_markedForTheCallOnly() throws Exception {
try (var c = RestClient.create().rootUrl(url).build()) {
var context = new BasicHttpContext();
- var rc = c.get(url + "/hello").context(context);
- rc.ssrfGuard();
- var ex = assertThrows(Exception.class, rc::run);
- assertContains("No allowed address for host '2130706433'", messages(ex));
+ try (var rc = c.get(url + "/hello")) {
+ rc.context(context);
+ rc.ssrfGuard();
+ var ex = assertThrows(Exception.class, rc::run);
+ assertContains("No allowed address for host '2130706433'", messages(ex));
+ }
assertNull(context.getAttribute(SsrfGuardMarker.ATTRIBUTE));
}
}
@@ -1152,60 +1209,60 @@ class RestClient_ConnectionManager_Test {
}
@Test void k24_guardedRedirect_noContext_crossOrigin_interceptorAndDefaultHeadersStripped() throws Exception {
- try (var server = new RoutedServer("https://93.184.216.35/end")) {
+ try (var routed = new RoutedServer("https://93.184.216.35/end")) {
var b = HttpClientBuilder.create().setDefaultHeaders(List.of(new BasicHeader("X-API-Key", "dflt")))
.addInterceptorLast((HttpRequestInterceptor)(r, x) -> r.setHeader("Authorization", "Bearer itcp"));
- try (var c = server.client(RestClient.create().httpClientBuilder(b))) {
- assertEquals(200, server.guarded(c, null));
+ try (var c = routed.client(RestClient.create().httpClientBuilder(b))) {
+ assertEquals(200, routed.guarded(c, null));
}
- assertEquals("93.184.216.34:Bearer itcp|dflt,93.184.216.35:null|null", server.hops());
+ assertEquals("93.184.216.34:Bearer itcp|dflt,93.184.216.35:null|null", routed.hops());
// Real Apache execution: each hop was pinned to its own (public) address.
- assertEquals("[/93.184.216.34:443, /93.184.216.35:443]", server.connects.toString());
+ assertEquals("[/93.184.216.34:443, /93.184.216.35:443]", routed.connects.toString());
}
}
@Test void k25_guardedRedirect_noContext_sameOrigin_interceptorAndDefaultHeadersKept() throws Exception {
- try (var server = new RoutedServer("https://93.184.216.34/end")) {
+ try (var routed = new RoutedServer("https://93.184.216.34/end")) {
var b = HttpClientBuilder.create().setDefaultHeaders(List.of(new BasicHeader("X-API-Key", "dflt")))
.addInterceptorLast((HttpRequestInterceptor)(r, x) -> r.setHeader("Authorization", "Bearer itcp"));
- try (var c = server.client(RestClient.create().httpClientBuilder(b))) {
- assertEquals(200, server.guarded(c, null));
+ try (var c = routed.client(RestClient.create().httpClientBuilder(b))) {
+ assertEquals(200, routed.guarded(c, null));
}
- assertEquals("93.184.216.34:Bearer itcp|dflt,93.184.216.34:Bearer itcp|dflt", server.hops());
+ assertEquals("93.184.216.34:Bearer itcp|dflt,93.184.216.34:Bearer itcp|dflt", routed.hops());
}
}
@Test void k26_guardedRedirect_callerContext_crossOrigin_targetAuthStateReset() throws Exception {
- try (var server = new RoutedServer("https://93.184.216.35/end")) {
- server.challenge = true;
- try (var c = server.client(RestClient.create().basicAuth("93.184.216.34", 443, "user", "pw"))) {
- assertEquals(200, server.guarded(c, HttpClientContext.create()));
+ try (var routed = new RoutedServer("https://93.184.216.35/end")) {
+ routed.challenge = true;
+ try (var c = routed.client(RestClient.create().basicAuth("93.184.216.34", 443, "user", "pw"))) {
+ assertEquals(200, routed.guarded(c, HttpClientContext.create()));
}
// Challenged, answered for the first host only; the answer is not carried to the second.
- assertEquals("93.184.216.34:null|null,93.184.216.34:Basic dXNlcjpwdw==|null,93.184.216.35:null|null", server.hops());
+ assertEquals("93.184.216.34:null|null,93.184.216.34:Basic dXNlcjpwdw==|null,93.184.216.35:null|null", routed.hops());
}
}
@Test void k27_guardedRedirect_callerContext_sameOrigin_targetAuthStateKept() throws Exception {
- try (var server = new RoutedServer("https://93.184.216.34/end")) {
- server.challenge = true;
- try (var c = server.client(RestClient.create().basicAuth("93.184.216.34", 443, "user", "pw"))) {
- assertEquals(200, server.guarded(c, HttpClientContext.create()));
+ try (var routed = new RoutedServer("https://93.184.216.34/end")) {
+ routed.challenge = true;
+ try (var c = routed.client(RestClient.create().basicAuth("93.184.216.34", 443, "user", "pw"))) {
+ assertEquals(200, routed.guarded(c, HttpClientContext.create()));
}
- assertEquals("93.184.216.34:null|null,93.184.216.34:Basic dXNlcjpwdw==|null,93.184.216.34:Basic dXNlcjpwdw==|null", server.hops());
+ assertEquals("93.184.216.34:null|null,93.184.216.34:Basic dXNlcjpwdw==|null,93.184.216.34:Basic dXNlcjpwdw==|null", routed.hops());
}
}
@Test void k28_guardedRedirect_reusedCallerContext_originIsTheCallsFirstHop() throws Exception {
- try (var server = new RoutedServer("https://93.184.216.35/end")) {
+ try (var routed = new RoutedServer("https://93.184.216.35/end")) {
var b = HttpClientBuilder.create().addInterceptorLast((HttpRequestInterceptor)(r, x) -> r.setHeader("Authorization", "Bearer itcp"));
- try (var c = server.client(RestClient.create().httpClientBuilder(b))) {
+ try (var c = routed.client(RestClient.create().httpClientBuilder(b))) {
var context = HttpClientContext.create();
// An earlier ordinary call with the same context, to the host the guarded call is later redirected to.
assertEquals(200, status(c, context, "https://93.184.216.35/end"));
- assertEquals(200, server.guarded(c, context));
+ assertEquals(200, routed.guarded(c, context));
}
- assertEquals("93.184.216.35:Bearer itcp|null,93.184.216.34:Bearer itcp|null,93.184.216.35:null|null", server.hops());
+ assertEquals("93.184.216.35:Bearer itcp|null,93.184.216.34:Bearer itcp|null,93.184.216.35:null|null", routed.hops());
}
}
@@ -1233,11 +1290,11 @@ class RestClient_ConnectionManager_Test {
// guarded @Remote call (whose /start redirects to another origin) is refused before anything is sent, and an ordinary
// call still goes through.
private static void assertLateChangeRefused(java.util.function.Consumer<HttpClientBuilder> change, String expected) throws Exception {
- try (var server = new RoutedServer("https://93.184.216.35/end")) {
- try (var c = server.client(new LateChangeHttpClientBuilder(change).rootUrl("https://93.184.216.34"))) {
+ try (var routed = new RoutedServer("https://93.184.216.35/end")) {
+ try (var c = routed.client(new LateChangeHttpClientBuilder(change).rootUrl("https://93.184.216.34"))) {
var ex = assertThrows(Exception.class, () -> c.getRemote(StartRemote.class).start());
assertContains(expected, messages(ex));
- assertEquals("", server.hops());
+ assertEquals("", routed.hops());
assertEquals(200, status(c, null, "https://93.184.216.35/end"));
}
}
@@ -1250,6 +1307,9 @@ class RestClient_ConnectionManager_Test {
this.change = change;
}
@Override
+ @SuppressWarnings({
+ "resource" // The discarded client shares the builder's connection manager with the one returned, so it must stay open.
+ })
protected CloseableHttpClient createHttpClient() {
super.createHttpClient();
change.accept(httpClientBuilder());
@@ -1287,6 +1347,9 @@ class RestClient_ConnectionManager_Test {
httpServer.start();
}
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
RestClient client(RestClient.Builder<?> b) {
var port2 = httpServer.getAddress().getPort();
return b.sslSocketFactory(new LayeredConnectionSocketFactory() {
@@ -1309,13 +1372,17 @@ class RestClient_ConnectionManager_Test {
}
// Sends a guarded GET for https://93.184.216.34/start with the given context (null for none).
+ @SuppressWarnings({
+ "resource" // context() returns the request itself, which the try-with-resources closes.
+ })
int guarded(RestClient c, HttpContext context) throws Exception {
- var rc = c.get("https://93.184.216.34/start");
- if (context != null)
- rc.context(context);
- rc.ssrfGuard();
- try (var r = rc.run()) {
- return r.getStatusCode();
+ try (var rc = c.get("https://93.184.216.34/start")) {
+ if (context != null)
+ rc.context(context);
+ rc.ssrfGuard();
+ try (var r = rc.run()) {
+ return r.getStatusCode();
+ }
}
}
@@ -1332,6 +1399,9 @@ class RestClient_ConnectionManager_Test {
// Calls super.createHttpClient(), then sets an HttpProcessor on the builder and builds again.
static final class RebuildingHttpClientBuilder extends RestClient.Builder<RebuildingHttpClientBuilder> {
@Override
+ @SuppressWarnings({
+ "resource" // The discarded client shares the builder's connection manager with the one returned, so it must stay open.
+ })
protected CloseableHttpClient createHttpClient() {
super.createHttpClient();
httpClientBuilder().setHttpProcessor(HttpProcessorBuilder.create().build());
@@ -1342,12 +1412,15 @@ class RestClient_ConnectionManager_Test {
// Sends a guarded GET for http://93.184.216.34/start with credential headers (one in lower case: header names are
// case-insensitive) through RedirectingCallHandler, which
// answers /start with a 302 to the given location, /back with a 302 to /end on the first host, and /end with 200.
+ @SuppressWarnings({
+ "resource" // header() returns the request itself, which the try-with-resources closes.
+ })
private static List<RedirectingCallHandler.Hop> guardedRedirect(String location) throws Exception {
RedirectingCallHandler.HOPS.clear();
RedirectingCallHandler.location = location;
- try (var c = RestClient.create().callHandler(RedirectingCallHandler.class).build()) {
- var rc = c.get("http://93.184.216.34/start").header("Authorization", "Bearer secret").header("Cookie", "session=abc").header("x-api-key", "key")
- .header("Proxy-Authorization", "Basic proxy");
+ try (var c = RestClient.create().callHandler(RedirectingCallHandler.class).build();
+ var rc = c.get("http://93.184.216.34/start").header("Authorization", "Bearer secret").header("Cookie", "session=abc").header("x-api-key", "key")
+ .header("Proxy-Authorization", "Basic proxy")) {
rc.ssrfGuard();
try (var r = rc.run()) {
assertEquals(200, r.getStatusCode());
@@ -1388,6 +1461,9 @@ class RestClient_ConnectionManager_Test {
// Overrides build(), returning the client super.build() built.
static final class SuperBuildHttpClientBuilder extends HttpClientBuilder {
@Override
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
public CloseableHttpClient build() {
return super.build();
}
@@ -1396,6 +1472,9 @@ class RestClient_ConnectionManager_Test {
// Swaps the connection manager and request executor at the exec-chain layer; build() itself is not overridden.
static final class MainExecSwapHttpClientBuilder extends HttpClientBuilder {
@Override
+ @SuppressWarnings({
+ "resource" // The connection manager is handed to the exec chain, which owns it.
+ })
protected ClientExecChain createMainExec(HttpRequestExecutor requestExec, HttpClientConnectionManager connManager,
ConnectionReuseStrategy reuseStrategy, ConnectionKeepAliveStrategy keepAliveStrategy, HttpProcessor proxyHttpProcessor,
AuthenticationStrategy targetAuthStrategy, AuthenticationStrategy proxyAuthStrategy, UserTokenHandler userTokenHandler) {
@@ -1426,6 +1505,9 @@ class RestClient_ConnectionManager_Test {
// Calls super.createHttpClient(), then returns a client of its own.
static final class OtherHttpClientBuilder extends RestClient.Builder<OtherHttpClientBuilder> {
@Override
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
protected CloseableHttpClient createHttpClient() {
try {
super.createHttpClient().close();
@@ -1439,6 +1521,9 @@ class RestClient_ConnectionManager_Test {
// Calls super.createHttpClient(), then returns a wrapper around a client of its own.
static final class WrappingHttpClientBuilder extends RestClient.Builder<WrappingHttpClientBuilder> {
@Override
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
protected CloseableHttpClient createHttpClient() {
try {
super.createHttpClient().close();
@@ -1452,6 +1537,9 @@ class RestClient_ConnectionManager_Test {
// Returns the client super.createHttpClient() built.
static final class SuperHttpClientBuilder extends RestClient.Builder<SuperHttpClientBuilder> {
@Override
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
protected CloseableHttpClient createHttpClient() {
return super.createHttpClient();
}
@@ -1460,6 +1548,9 @@ class RestClient_ConnectionManager_Test {
// Builds the client it was configured for, then returns another one.
static final class OtherClientHttpClientBuilder extends HttpClientBuilder {
@Override
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
public CloseableHttpClient build() {
try {
super.build().close();
@@ -1473,6 +1564,9 @@ class RestClient_ConnectionManager_Test {
// Replaces the connection manager it was given before building.
static final class SwappingHttpClientBuilder extends HttpClientBuilder {
@Override
+ @SuppressWarnings({
+ "resource" // The connection manager is handed to the built client, which owns it.
+ })
public CloseableHttpClient build() {
setConnectionManager(new PoolingHttpClientConnectionManager());
return super.build();
@@ -1480,7 +1574,8 @@ class RestClient_ConnectionManager_Test {
}
@SuppressWarnings({
- "deprecation" // getParams() and getConnectionManager() are abstract in CloseableHttpClient.
+ "deprecation", // getParams() and getConnectionManager() are abstract in CloseableHttpClient.
+ "resource" // The wrapped client is owned by this wrapper and closed in close(); doExecute() returns the response to the caller.
})
static final class WrappingHttpClient extends CloseableHttpClient {
private final CloseableHttpClient inner;
@@ -1560,8 +1655,14 @@ class RestClient_ConnectionManager_Test {
return List.of(ordinaryPool(c), pinnedPool(c));
}
+ private static String fetch(RestClient c, String uri) throws Exception {
+ try (var req = c.get(uri); var res = req.run()) {
+ return res.getContent().asString();
+ }
+ }
+
private static void assertPlainOk(RestClient c) throws Exception {
- assertEquals("hi", c.get(url + "/hello").run().getContent().asString());
+ assertEquals("hi", fetch(c, url + "/hello"));
}
private static void assertGuardedRejected(RestClient c) {
@@ -1569,6 +1670,9 @@ class RestClient_ConnectionManager_Test {
assertContains("No allowed address for host '2130706433'", messages(ex));
}
+ @SuppressWarnings({
+ "resource" // The leased connection goes back to the pool through releaseConnection(), not close().
+ })
private static void assertOpen(HttpClientConnectionManager pool) throws Exception {
var conn = pool.requestConnection(new HttpRoute(new HttpHost("127.0.0.1", port)), null).get(1, TimeUnit.SECONDS);
pool.releaseConnection(conn, null, 0, TimeUnit.SECONDS);
@@ -1576,7 +1680,14 @@ class RestClient_ConnectionManager_Test {
private static void assertShutDown(HttpClientConnectionManager pool) {
var route = new HttpRoute(new HttpHost("127.0.0.1", port));
- assertThrows(IllegalStateException.class, () -> pool.requestConnection(route, null).get(1, TimeUnit.SECONDS));
+ assertThrows(IllegalStateException.class, () -> lease(pool, route));
+ }
+
+ @SuppressWarnings({
+ "resource" // The test only needs the lease to succeed or throw; the connection is never used.
+ })
+ private static void lease(HttpClientConnectionManager pool, HttpRoute route) throws Exception {
+ pool.requestConnection(route, null).get(1, TimeUnit.SECONDS);
}
private static HttpClientConnectionManager ordinaryPool(RestClient c) throws Exception {
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_Coverage2_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_Coverage2_Test.java
index 08ac755e92..80057ba2c5 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_Coverage2_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_Coverage2_Test.java
@@ -373,9 +373,9 @@ class RestClient_Coverage2_Test {
}
@Test void a22_onCallClose_checkedException_wrappedThenLoggedNotThrown() throws Exception {
- // RestCallException extends org.apache.http.HttpException, a CHECKED exception, so RestResponse#close's own
- // try/catch (RuntimeException rethrown, everything else logged) swallows it -- proving the generic-exception
- // wrapping branch of onCallClose executes without asserting on a exception type that never surfaces to the caller.
+ // RestCallException extends org.apache.http.HttpException, a CHECKED exception, so the close method of RestResponse
+ // rethrows runtime exceptions but logs everything else, and so swallows it. That proves the generic-exception
+ // wrapping branch of onCallClose executes, without asserting on an exception type that never reaches the caller.
try (var out = new ByteArrayOutputStream();
var c = RestClient.create().interceptors(new ThrowingOnCloseInterceptor()).logToConsole().console(new PrintStream(out)).build();
var req = c.get(url() + "/echo");
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_SsrfGuard_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_SsrfGuard_Test.java
index 8f389b9ac3..7045cf1842 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_SsrfGuard_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestClient_SsrfGuard_Test.java
@@ -55,11 +55,11 @@ class RestClient_SsrfGuard_Test {
// Explicit IPv4 loopback bind, as in RestClient_Coverage2_Test.
server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
server.createContext("/hello", exchange -> {
- exchange.getRequestBody().readAllBytes();
+ try (var in = exchange.getRequestBody()) { in.readAllBytes(); }
var body = "hi".getBytes(StandardCharsets.UTF_8);
// A fixed Content-Length keeps the connection alive for reuse once the body is consumed.
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
});
server.start();
@@ -136,6 +136,9 @@ class RestClient_SsrfGuard_Test {
// B: a connection manager this RestClient did not create cannot be pinned, so guarded calls are refused
// =================================================================================================================
+ @SuppressWarnings({
+ "resource" // The caller-supplied manager is owned by the client built from it.
+ })
@Test void b01_callerSuppliedConnectionManager_guardActive_refused() throws Exception {
try (var c = RestClient.create().rootUrl(url).connectionManager(new PoolingHttpClientConnectionManager()).build()) {
assertGuardedRefused(c);
@@ -159,6 +162,9 @@ class RestClient_SsrfGuard_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The caller-supplied manager is owned by the client built from it.
+ })
@Test void b04_callerSuppliedConnectionManager_allowPrivateUrls_succeeds() throws Exception {
try (var c = RestClient.create().rootUrl(url).connectionManager(new PoolingHttpClientConnectionManager()).allowPrivateUrls(true).build()) {
assertEquals("hi", c.getRemote(HelloRemote.class).call());
@@ -177,6 +183,9 @@ class RestClient_SsrfGuard_Test {
// C: the two-pool router sends each operation to the right pool
// =================================================================================================================
+ @SuppressWarnings({
+ "resource" // The leased connection goes back to the router through releaseConnection(), not close().
+ })
@Test void c01_router_guardedLease_allOperationsGoToPinnedPool() throws Exception {
var ordinary = new Recorder("ordinary");
var pinned = new Recorder("pinned");
@@ -200,6 +209,9 @@ class RestClient_SsrfGuard_Test {
assertEquals("[]", ordinary.calls.toString());
}
+ @SuppressWarnings({
+ "resource" // The leased connection goes back to the router through releaseConnection(), not close().
+ })
@Test void c02_router_unguardedLease_allOperationsGoToOrdinaryPool() throws Exception {
var ordinary = new Recorder("ordinary");
var pinned = new Recorder("pinned");
@@ -285,6 +297,9 @@ class RestClient_SsrfGuard_Test {
}
}
+ @SuppressWarnings({
+ "resource" // The pool is owned and closed by the client; the test only inspects it.
+ })
@Test void d02_pooled_settingsChangedAfterBuild_mirroredOnNextGuardedLease() throws Exception {
var holder = new HttpClientConnectionManager[1];
try (var c = new ConfiguringBuilder(cm -> holder[0] = cm).rootUrl(url).pooled().build()) {
@@ -368,6 +383,9 @@ class RestClient_SsrfGuard_Test {
// F: the pinned pool is always this client's own, so closing the client shuts it down
// =================================================================================================================
+ @SuppressWarnings({
+ "resource" // The subject is close() itself, so the client is closed explicitly.
+ })
@Test void f01_connectionManagerShared_close_shutsDownBothOwnPools() throws Exception {
var c = RestClient.create().rootUrl(url).pooled().connectionManagerShared(true).build();
var router = routerOf(c);
@@ -375,19 +393,25 @@ class RestClient_SsrfGuard_Test {
var pinned = (HttpClientConnectionManager)field(router, "pinned");
c.close();
var route = new HttpRoute(new HttpHost("localhost", 80));
- assertThrows(IllegalStateException.class, () -> pinned.requestConnection(route, null).get(1, TimeUnit.SECONDS));
+ assertThrows(IllegalStateException.class, () -> lease(pinned, route));
// The ordinary pool was built by this client and nothing else can reach it, so "shared" does not keep it open.
- assertThrows(IllegalStateException.class, () -> ordinary.requestConnection(route, null).get(1, TimeUnit.SECONDS));
+ assertThrows(IllegalStateException.class, () -> lease(ordinary, route));
}
+ @SuppressWarnings({
+ "resource" // The subject is closeQuietly() itself, so the client is closed explicitly.
+ })
@Test void f02_closeQuietly_shutsDownPinnedPool() throws Exception {
var c = RestClient.create().rootUrl(url).connectionManagerShared(true).build();
var pinned = (HttpClientConnectionManager)field(routerOf(c), "pinned");
c.closeQuietly();
var route = new HttpRoute(new HttpHost("localhost", 80));
- assertThrows(IllegalStateException.class, () -> pinned.requestConnection(route, null).get(1, TimeUnit.SECONDS));
+ assertThrows(IllegalStateException.class, () -> lease(pinned, route));
}
+ @SuppressWarnings({
+ "resource" // The subject is close() itself; the leased connection goes back through releaseConnection().
+ })
@Test void f03_keepHttpClientOpen_close_leavesPinnedPoolOpen() throws Exception {
var c = RestClient.create().rootUrl(url).keepHttpClientOpen().build();
var pinned = (HttpClientConnectionManager)field(routerOf(c), "pinned");
@@ -402,6 +426,9 @@ class RestClient_SsrfGuard_Test {
// Helpers
// =================================================================================================================
+ @SuppressWarnings({
+ "resource" // The client is returned to the caller, which owns it.
+ })
private static RestClient client(boolean pooled) {
var b = RestClient.create().rootUrl(url);
if (pooled)
@@ -410,7 +437,9 @@ class RestClient_SsrfGuard_Test {
}
private static void assertPlainOk(RestClient c) throws Exception {
- assertEquals("hi", c.get(url + "/hello").run().getContent().asString());
+ try (var req = c.get(url + "/hello"); var res = req.run()) {
+ assertEquals("hi", res.getContent().asString());
+ }
}
private static void assertGuardedRejected(RestClient c) {
@@ -427,6 +456,13 @@ class RestClient_SsrfGuard_Test {
}
// The two-pool router installed on the client's HttpClient (read reflectively: neither exposes it).
+ @SuppressWarnings({
+ "resource" // The test only needs the lease to succeed or throw; the connection is never used.
+ })
+ private static void lease(HttpClientConnectionManager manager, HttpRoute route) throws Exception {
+ manager.requestConnection(route, null).get(1, TimeUnit.SECONDS);
+ }
+
private static Object routerOf(RestClient c) throws Exception {
var router = field(c.httpClient, "connManager");
assertEquals("SsrfGuardConnectionManager", router.getClass().getSimpleName());
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestRequest_Rethrow_Coverage_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestRequest_Rethrow_Coverage_Test.java
index f625b3b0ea..ab7a1887e8 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestRequest_Rethrow_Coverage_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/RestRequest_Rethrow_Coverage_Test.java
@@ -69,6 +69,10 @@ class RestRequest_Rethrow_Coverage_Test {
/** Has an {@code (HttpResponse)} constructor that fails for a reason other than a status mismatch, plus a {@code (String)} fallback. */
public static class ExcWithFailingResponseCtor extends RuntimeException {
private static final long serialVersionUID = 1L;
+ @SuppressWarnings({
+ "java:S1172", // The (HttpResponse) signature is what the rethrow resolution looks up reflectively.
+ "unused" // Same: the parameter exists only to select this constructor.
+ })
public ExcWithFailingResponseCtor(org.apache.http.HttpResponse r) { throw new IllegalStateException("boom"); }
public ExcWithFailingResponseCtor(String msg) { super(msg); }
}
diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException_Test.java
index dfd0fcae63..c1dd4a8bc7 100644
--- a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException_Test.java
+++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/remote/RemoteMetadataException_Test.java
@@ -43,4 +43,16 @@ class RemoteMetadataException_Test {
assertFalse(e.getMessage().contains("on method"), "Unexpected message: " + e.getMessage());
assertTrue(e.getMessage().contains("Bad thing: reason"), "Unexpected message: " + e.getMessage());
}
+
+ @Test void a03_nullClass_stillYieldsReadableMessage() {
+ var e = new RemoteMetadataException((Class<?>)null, "Bad thing: %s", "reason");
+ assertTrue(e.getMessage().contains("Invalid remote definition found on class null"), "Unexpected message: " + e.getMessage());
+ assertTrue(e.getMessage().contains("Bad thing: reason"), "Unexpected message: " + e.getMessage());
+ }
+
+ @Test void a04_nullMethod_stillYieldsReadableMessage() {
+ var e = new RemoteMetadataException((java.lang.reflect.Method)null, "Bad thing: %s", "reason");
+ assertTrue(e.getMessage().contains("Invalid remote definition found on class null"), "Unexpected message: " + e.getMessage());
+ assertTrue(e.getMessage().contains("Bad thing: reason"), "Unexpected message: " + e.getMessage());
+ }
}
diff --git a/juneau-rest/juneau-rest-client-jetty/src/main/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpRequest.java b/juneau-rest/juneau-rest-client-jetty/src/main/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpRequest.java
index fa65bafa77..e7f925919a 100644
--- a/juneau-rest/juneau-rest-client-jetty/src/main/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpRequest.java
+++ b/juneau-rest/juneau-rest-client-jetty/src/main/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpRequest.java
@@ -62,6 +62,9 @@ final class CredentialGuardingHttpRequest extends HttpRequest {
}
@Override /* HttpRequest */
+ @SuppressWarnings({
+ "resource" // the new request is returned to the caller, which owns it.
+ })
protected HttpRequest copyInstance(URI newURI) {
return new CredentialGuardingHttpRequest(getHttpClient(), getConversation(), newURI);
}
diff --git a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/JettyHttpTransport_SsrfGuard_Test.java b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/JettyHttpTransport_SsrfGuard_Test.java
index 664b0d20cd..6a6e9630b1 100644
--- a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/JettyHttpTransport_SsrfGuard_Test.java
+++ b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/JettyHttpTransport_SsrfGuard_Test.java
@@ -49,6 +49,9 @@ class JettyHttpTransport_SsrfGuard_Test {
}
@Test
+ @SuppressWarnings({
+ "resource" // the caller-supplied client is owned by the transport, which the try-with-resources closes.
+ })
void a02_supportsUrlPolicy_callerSuppliedClient_false() throws Exception {
try (var transport = JettyHttpTransport.builder().httpClient(new HttpClient()).build()) {
assertFalse(transport.supportsUrlPolicy());
@@ -201,7 +204,7 @@ class JettyHttpTransport_SsrfGuard_Test {
server.createContext("/hello", exchange -> {
var body = "hi".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
});
server.start();
@@ -209,9 +212,9 @@ class JettyHttpTransport_SsrfGuard_Test {
}
private static void assertPlainOk(JettyHttpTransport transport, TransportRequest plain) throws Exception {
- try (var response = transport.execute(plain)) {
+ try (var response = transport.execute(plain); var in = response.getBody()) {
assertEquals(200, response.getStatusCode());
- assertEquals("hi", new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8));
+ assertEquals("hi", new String(in.readAllBytes(), StandardCharsets.UTF_8));
}
}
diff --git a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpClient_Test.java b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpClient_Test.java
index 5f2b7d07e6..6ec84bb6d8 100644
--- a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpClient_Test.java
+++ b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/CredentialGuardingHttpClient_Test.java
@@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.*;
import java.net.*;
-import org.apache.juneau.rest.client.*;
import org.eclipse.jetty.client.*;
import org.junit.jupiter.api.*;
@@ -68,7 +67,9 @@ class CredentialGuardingHttpClient_Test {
void a04_underscoreHostRedirectTarget_rejectedByJettyBeforeTheOriginCheck() {
// java.net.URI parses an underscore host name with a null host, and Jetty refuses to build a request for a null
// host, so a redirect to such a host fails in Jetty itself and never reaches this client's origin comparison.
- var ex = assertThrows(IllegalArgumentException.class, () -> client.copyRequest(oldRequest(), URI.create("http://my_service:8080/next")));
+ var old = oldRequest();
+ var next = URI.create("http://my_service:8080/next");
+ var ex = assertThrows(IllegalArgumentException.class, () -> client.copyRequest(old, next));
assertTrue(ex.getMessage().contains("Invalid URI host"), ex.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/PolicyPinningSocketAddressResolver_Test.java b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/PolicyPinningSocketAddressResolver_Test.java
index 8e0ab3d5dc..5c450a84da 100644
--- a/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/PolicyPinningSocketAddressResolver_Test.java
+++ b/juneau-rest/juneau-rest-client-jetty/src/test/java/org/apache/juneau/rest/client/jetty/PolicyPinningSocketAddressResolver_Test.java
@@ -134,7 +134,7 @@ class PolicyPinningSocketAddressResolver_Test {
var a = PolicyPinningSocketAddressResolver.tagFor(org.apache.juneau.http.remote.RemoteUrlPolicy.AllowedRanges.of("198.18.0.0/15"));
var b = PolicyPinningSocketAddressResolver.tagFor(org.apache.juneau.http.remote.RemoteUrlPolicy.AllowedRanges.of("198.18.0.0/15"));
assertEquals(a, b);
- assertNotEquals(a, PolicyPinningSocketAddressResolver.PINNED_TAG);
+ assertNotEquals(PolicyPinningSocketAddressResolver.PINNED_TAG, a);
assertSame(PolicyPinningSocketAddressResolver.PINNED_TAG, PolicyPinningSocketAddressResolver.tagFor(org.apache.juneau.http.remote.RemoteUrlPolicy.AllowedRanges.NONE));
}
}
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpAuthorizationCodeAcquirer_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpAuthorizationCodeAcquirer_Test.java
index 0e889bf3fe..705a1b02eb 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpAuthorizationCodeAcquirer_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpAuthorizationCodeAcquirer_Test.java
@@ -27,6 +27,8 @@ import java.util.concurrent.atomic.*;
import org.apache.juneau.*;
import org.apache.juneau.rest.auth.oauth.flow.*;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.pkce.*;
@@ -400,7 +402,7 @@ class McpAuthorizationCodeAcquirer_Test extends TestBase {
}
}
- @Test void e02_requireIssuerParameterRejectsCallbackWithoutIss() throws IOException {
+ @Test void e02_requireIssuerParameterRejectsCallbackWithoutIss() {
// With requireIssuerResponseParameter(true) the end-to-end flow must reject a callback that omits iss.
var acquirer = minimal()
.requireIssuerResponseParameter(true)
@@ -416,14 +418,16 @@ class McpAuthorizationCodeAcquirer_Test extends TestBase {
}
})
.build();
- var e = assertThrows(McpAuthException.class, () -> acquirer.acquire(Duration.ofSeconds(5)));
+ var timeout = Duration.ofSeconds(5);
+ var e = assertThrows(McpAuthException.class, () -> acquirer.acquire(timeout));
assertTrue(e.getMessage().contains("missing the required iss"), e::getMessage);
}
@Test void e03_acquireFailsWhenFixedPortInUse() throws IOException {
try (var occupied = new ServerSocket(0, 0, InetAddress.getLoopbackAddress())) {
var acquirer = minimal().redirectPort(occupied.getLocalPort()).build();
- var e = assertThrows(McpAuthException.class, () -> acquirer.acquire(Duration.ofMillis(100)));
+ var timeout = Duration.ofMillis(100);
+ var e = assertThrows(McpAuthException.class, () -> acquirer.acquire(timeout));
assertTrue(e.getMessage().contains("loopback redirect listener"), e::getMessage);
}
}
@@ -437,7 +441,8 @@ class McpAuthorizationCodeAcquirer_Test extends TestBase {
.authorizationEndpoint(URI.create("https://idp.example.com/authorize"))
.tokenEndpoint(URI.create("https://idp.example.com/token"))
.clientId("cli-app").resource(RESOURCE).expectedIssuer(ISSUER).build();
- assertThrows(McpAuthException.class, () -> acquirer.acquire(Duration.ofMillis(100)));
+ var timeout = Duration.ofMillis(100);
+ assertThrows(McpAuthException.class, () -> acquirer.acquire(timeout));
} finally {
System.setOut(original);
}
@@ -446,28 +451,18 @@ class McpAuthorizationCodeAcquirer_Test extends TestBase {
assertTrue(out.contains("https://idp.example.com/authorize"), out);
}
- @Test void e05_handleCallbackMissingStateRejected() {
+ @ParameterizedTest
+ @CsvSource(delimiter = '|', value = {
+ "http://127.0.0.1:1/callback?code=the-code | missing the state",
+ "http://127.0.0.1:1/callback?code=the-code&state=never-issued | unknown, expired, or replayed",
+ "http://127.0.0.1:1/callback | could not be parsed" // No parameters at all.
+ })
+ void e05_handleCallbackRejected(String callback, String expectedMessage) {
var acquirer = minimal().build();
var flow = flowFor(URI.create("https://idp.example.com/token"));
- var cb = URI.create("http://127.0.0.1:1/callback?code=the-code");
- var e = assertThrows(McpAuthException.class, () -> acquirer.handleCallback(flow, cb));
- assertTrue(e.getMessage().contains("missing the state"), e::getMessage);
- }
-
- @Test void e06_handleCallbackUnknownStateRejected() {
- var acquirer = minimal().build();
- var flow = flowFor(URI.create("https://idp.example.com/token"));
- var cb = URI.create("http://127.0.0.1:1/callback?code=the-code&state=never-issued");
+ var cb = URI.create(callback);
var e = assertThrows(McpAuthException.class, () -> acquirer.handleCallback(flow, cb));
- assertTrue(e.getMessage().contains("unknown, expired, or replayed"), e::getMessage);
- }
-
- @Test void e07_handleCallbackUnparseableRejected() {
- var acquirer = minimal().build();
- var flow = flowFor(URI.create("https://idp.example.com/token"));
- var cb = URI.create("http://127.0.0.1:1/callback"); // no parameters at all
- var e = assertThrows(McpAuthException.class, () -> acquirer.handleCallback(flow, cb));
- assertTrue(e.getMessage().contains("could not be parsed"), e::getMessage);
+ assertTrue(e.getMessage().contains(expectedMessage), e::getMessage);
}
@Test void e08_validateMissingStateParamIsCsrfMismatch() {
@@ -546,7 +541,8 @@ class McpAuthorizationCodeAcquirer_Test extends TestBase {
assertThrows(IllegalArgumentException.class, () -> b.clientSecret(" "));
assertThrows(IllegalArgumentException.class, () -> b.scope(" "));
assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ofSeconds(-1)));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(negative));
}
@Test void e14_validFixedRedirectPortAccepted() {
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpClientRegistrationManager_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpClientRegistrationManager_Test.java
index 0004489196..bac9d5b525 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpClientRegistrationManager_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpClientRegistrationManager_Test.java
@@ -168,7 +168,8 @@ class McpClientRegistrationManager_Test extends TestBase {
assertThrows(IllegalArgumentException.class, () -> b.clientName(" "));
assertThrows(IllegalArgumentException.class, () -> b.initialAccessToken(" "));
assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ofSeconds(-1)));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(negative));
}
/** Runs the real DCR path (no override) against a loopback stub, capturing the registration request. */
@@ -234,7 +235,7 @@ class McpClientRegistrationManager_Test extends TestBase {
var auth = new AtomicReference<String>();
server.createContext("/register", ex -> {
auth.set(ex.getRequestHeaders().getFirst("Authorization"));
- ex.getRequestBody().readAllBytes();
+ try (var in = ex.getRequestBody()) { in.readAllBytes(); }
var b = "{\"client_id\":\"plain\",\"redirect_uris\":[\"http://127.0.0.1:3000/callback\"]}"
.getBytes(StandardCharsets.UTF_8);
ex.getResponseHeaders().add("Content-Type", "application/json");
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpDynamicClientRegistrar_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpDynamicClientRegistrar_Test.java
index c378ef8a69..d67cf582b0 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpDynamicClientRegistrar_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpDynamicClientRegistrar_Test.java
@@ -232,7 +232,8 @@ class McpDynamicClientRegistrar_Test extends TestBase {
assertThrows(IllegalArgumentException.class, () -> b.clientName(" "));
assertThrows(IllegalArgumentException.class, () -> b.initialAccessToken(" "));
assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ofSeconds(-1)));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(negative));
}
@Test void e05_toStringWithoutInitialAccessToken() {
@@ -270,7 +271,9 @@ class McpDynamicClientRegistrar_Test extends TestBase {
@Test void f05_errorWithoutDescriptionOmitsParenthetical() {
var body = "{\"error\":\"invalid_client_metadata\"}";
- var e = assertThrows(McpAuthException.class, () -> base().build().parseRegistrationResponse(jsonResponse(400, body)));
+ var registrar = base().build();
+ var response = jsonResponse(400, body);
+ var e = assertThrows(McpAuthException.class, () -> registrar.parseRegistrationResponse(response));
assertFalse(e.getMessage().contains("("), e::getMessage);
}
@@ -281,7 +284,7 @@ class McpDynamicClientRegistrar_Test extends TestBase {
var auth = new AtomicReference<String>();
server.createContext("/register", ex -> {
auth.set(ex.getRequestHeaders().getFirst("Authorization"));
- ex.getRequestBody().readAllBytes();
+ try (var in = ex.getRequestBody()) { in.readAllBytes(); }
var b = ("{\"client_id\":\"live\",\"redirect_uris\":[\"http://127.0.0.1:3000/callback\"],"
+ "\"application_type\":\"native\"}").getBytes(StandardCharsets.UTF_8);
ex.getResponseHeaders().add("Content-Type", "application/json");
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpProtectedResourceMetadataClient_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpProtectedResourceMetadataClient_Test.java
index 7bf7737d46..402e942cfc 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpProtectedResourceMetadataClient_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpProtectedResourceMetadataClient_Test.java
@@ -208,7 +208,8 @@ class McpProtectedResourceMetadataClient_Test extends TestBase {
@Test void e01_httpTimeoutMustBePositive() {
var b = McpProtectedResourceMetadataClient.create();
assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ofSeconds(-1)));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(negative));
assertDoesNotThrow(() -> b.httpTimeout(Duration.ofSeconds(3)));
}
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpTokenProvider_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpTokenProvider_Test.java
index d2bc3ddb01..bc0159b748 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpTokenProvider_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/McpTokenProvider_Test.java
@@ -311,7 +311,8 @@ class McpTokenProvider_Test extends TestBase {
@Test void e04_httpTimeoutMustBePositive() {
var b = McpTokenProvider.clientCredentials();
assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(Duration.ofSeconds(-1)));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.httpTimeout(negative));
}
@Test void e05_injectedClockDrivesExpiry() {
diff --git a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/WwwAuthenticateChallenge_Test.java b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/WwwAuthenticateChallenge_Test.java
index 4d696d1da3..c1e1a37cb1 100644
--- a/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/WwwAuthenticateChallenge_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-auth/src/test/java/org/apache/juneau/rest/client/mcp/auth/WwwAuthenticateChallenge_Test.java
@@ -23,6 +23,8 @@ import java.util.*;
import org.apache.juneau.*;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
/**
* Tests for {@link WwwAuthenticateChallenge} (RFC 6750 / RFC 9728 challenge parsing).
@@ -80,8 +82,14 @@ class WwwAuthenticateChallenge_Test extends TestBase {
assertEquals("Basic", c.scheme());
}
- @Test void b05_missingResourceMetadataIsEmpty() {
- var c = WwwAuthenticateChallenge.parse("Bearer realm=\"mcp\"").orElseThrow();
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "Bearer realm=\"mcp\"", // Missing.
+ "Bearer resource_metadata=\"not a uri\"", // Unparseable.
+ "Bearer resource_metadata=\"\"" // Blank.
+ })
+ void b05_missingOrUnusableResourceMetadataIsEmpty(String header) {
+ var c = WwwAuthenticateChallenge.parse(header).orElseThrow();
assertTrue(c.resourceMetadata().isEmpty());
}
@@ -137,16 +145,6 @@ class WwwAuthenticateChallenge_Test extends TestBase {
assertEquals("abc", c.parameter("a").orElseThrow());
}
- @Test void c10_unparseableResourceMetadataIsEmpty() {
- var c = WwwAuthenticateChallenge.parse("Bearer resource_metadata=\"not a uri\"").orElseThrow();
- assertTrue(c.resourceMetadata().isEmpty());
- }
-
- @Test void c11_blankResourceMetadataIsEmpty() {
- var c = WwwAuthenticateChallenge.parse("Bearer resource_metadata=\"\"").orElseThrow();
- assertTrue(c.resourceMetadata().isEmpty());
- }
-
@Test void c12_blankScopeIsEmptySet() {
var c = WwwAuthenticateChallenge.parse("Bearer scope=\" \"").orElseThrow();
assertTrue(c.scopes().isEmpty());
diff --git a/juneau-rest/juneau-rest-client-mcp-v20260728/src/test/java/org/apache/juneau/rest/client/mcp/v20260728/McpClient_Coverage_Test.java b/juneau-rest/juneau-rest-client-mcp-v20260728/src/test/java/org/apache/juneau/rest/client/mcp/v20260728/McpClient_Coverage_Test.java
index 49a6010f5e..36eabcd131 100644
--- a/juneau-rest/juneau-rest-client-mcp-v20260728/src/test/java/org/apache/juneau/rest/client/mcp/v20260728/McpClient_Coverage_Test.java
+++ b/juneau-rest/juneau-rest-client-mcp-v20260728/src/test/java/org/apache/juneau/rest/client/mcp/v20260728/McpClient_Coverage_Test.java
@@ -31,6 +31,8 @@ import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.rest.client.*;
import org.apache.juneau.rest.client.mcp.*;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
import com.sun.net.httpserver.*;
@@ -362,30 +364,15 @@ class McpClient_Coverage_Test extends TestBase {
// e - duplex pump early exits
//-----------------------------------------------------------------------------------------------------------------
- @Test
- void e01_pumpNextServerMessage_emptyStream_returnsWithoutDispatch() throws Exception {
- var dispatched = new AtomicBoolean();
- try (var c = client(sse(""))) {
- c.setServerRequestHandler((request, ctx) -> { dispatched.set(true); return JsonMap.of(); });
- c.pumpNextServerMessage();
- }
- assertFalse(dispatched.get());
- }
-
- @Test
- void e02_pumpNextServerMessage_eventWithoutData_returnsWithoutDispatch() throws Exception {
- var dispatched = new AtomicBoolean();
- try (var c = client(sse("event: other\n\n"))) {
- c.setServerRequestHandler((request, ctx) -> { dispatched.set(true); return JsonMap.of(); });
- c.pumpNextServerMessage();
- }
- assertFalse(dispatched.get());
- }
-
- @Test
- void e03_pumpNextServerMessage_emptyDataEvent_returnsWithoutDispatch() throws Exception {
+ @ParameterizedTest(name = "[{index}] stream={0}")
+ @ValueSource(strings = {
+ "", // empty stream
+ "event: other\n\n", // event without data
+ "data:\n\n" // empty data event
+ })
+ void e01_pumpNextServerMessage_noDispatchableMessage_returnsWithoutDispatch(String body) throws Exception {
var dispatched = new AtomicBoolean();
- try (var c = client(sse("data:\n\n"))) {
+ try (var c = client(sse(body))) {
c.setServerRequestHandler((request, ctx) -> { dispatched.set(true); return JsonMap.of(); });
c.pumpNextServerMessage();
}
diff --git a/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpRedirectCredentialGuard.java b/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpRedirectCredentialGuard.java
index 2f4a98dea1..0914da3877 100644
--- a/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpRedirectCredentialGuard.java
+++ b/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpRedirectCredentialGuard.java
@@ -78,6 +78,9 @@ final class OkHttpRedirectCredentialGuard implements Interceptor {
* <p>
* OkHttp builds every retry and redirect hop with {@link Request#newBuilder()}, which carries the tag along.
*/
+ @SuppressWarnings({
+ "resource" // returned Response is owned and closed by OkHttp's call chain, not by this interceptor.
+ })
static final Interceptor FIRST_HOP_RECORDER = chain -> {
var request = chain.request();
return chain.proceed(request.newBuilder().tag(FirstHop.class, new FirstHop(request)).build());
@@ -99,6 +102,8 @@ final class OkHttpRedirectCredentialGuard implements Interceptor {
@Override /* Interceptor */
@SuppressWarnings({
+ "java:S135", // Guard clauses keep the redirect credential-strip check readable.
+ "java:S3776", // Single linear pass over the redirect hop's credential-stripping rules; splitting it would scatter them.
"resource" // returned Response is owned and closed by OkHttp's call chain, not by this interceptor.
})
public Response intercept(Chain chain) throws IOException {
diff --git a/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpTransport.java b/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpTransport.java
index 3523c471f0..70ab2fc847 100644
--- a/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpTransport.java
+++ b/juneau-rest/juneau-rest-client-okhttp/src/main/java/org/apache/juneau/rest/client/okhttp/OkHttpTransport.java
@@ -174,7 +174,13 @@ public final class OkHttpTransport implements HttpTransport {
var explicit = httpClient.proxy();
var uri = url.uri();
// Like OkHttp, skip the ProxySelector when java.net.URI cannot parse a host (e.g. an underscore host name).
- var proxies = explicit != null ? List.of(explicit) : uri.getHost() == null ? List.of(Proxy.NO_PROXY) : selectedProxies(uri);
+ List<Proxy> proxies;
+ if (explicit != null)
+ proxies = List.of(explicit);
+ else if (uri.getHost() == null)
+ proxies = List.of(Proxy.NO_PROXY);
+ else
+ proxies = selectedProxies(uri);
for (var p : proxies)
if (p.type() != Proxy.Type.DIRECT)
throw iaex("Request to '%s' would be routed through a proxy, which resolves the target host itself and bypasses the SSRF guard's address pinning; use a client without a proxy (or set allowPrivateUrls)", url.host());
diff --git a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_PolicyPath_Test.java b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_PolicyPath_Test.java
index d135e19c79..8bc822760d 100644
--- a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_PolicyPath_Test.java
+++ b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_PolicyPath_Test.java
@@ -48,6 +48,7 @@ import okio.BufferedSource;
* {@link SocketFactory} redirects every connect to a loopback server, recording the address the transport asked for.
*/
@SuppressWarnings({
+ "java:S3415", // Expected value is already first; Sonar mistakes the upper-case constant or field for the expected value
"resource" // Transport/response Closeables are exercised inline; lifecycle is managed by the test.
})
// SEPARATE_THREAD: a socket read blocked on a non-responding peer ignores interrupts, so SAME_THREAD would still hang.
@@ -134,7 +135,7 @@ class OkHttpTransport_PolicyPath_Test {
}
@Test
- void a04_guarded_redirectToLoopback_refusedBeforeConnect() throws Exception {
+ void a04_guarded_redirectToLoopback_refusedBeforeConnect() {
var connects = new CopyOnWriteArrayList<String>();
try (var transport = transport(connects)) {
var ex = assertThrows(TransportException.class, () -> transport.execute(guarded("http://8.8.8.8:" + port + "/to-loopback")).close());
@@ -149,7 +150,7 @@ class OkHttpTransport_PolicyPath_Test {
// =================================================================================================================
@Test
- void b01_bodyWiringFails_transportException_andResponseClosed() throws Exception {
+ void b01_bodyWiringFails_transportException_andResponseClosed() {
var sourceCalls = new AtomicInteger();
Interceptor breakBody = chain -> {
var response = chain.proceed(chain.request());
diff --git a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_RedirectCredentials_Test.java b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_RedirectCredentials_Test.java
index 31bc856cb1..4b5761fa35 100644
--- a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_RedirectCredentials_Test.java
+++ b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_RedirectCredentials_Test.java
@@ -40,6 +40,7 @@ import okhttp3.OkHttpClient;
* same-origin redirect.
*/
@SuppressWarnings({
+ "java:S3415", // Expected value is already first; Sonar mistakes the upper-case constant or field for the expected value
"resource" // Transport/client instances are short-lived test fixtures.
})
// SEPARATE_THREAD: a socket read blocked on a non-responding peer ignores interrupts, so SAME_THREAD would still hang.
@@ -214,7 +215,9 @@ class OkHttpTransport_RedirectCredentials_Test {
// BridgeInterceptor loads the target's own cookies from the client's CookieJar for each hop.
var jar = new CookieJar() {
@Override
- public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {}
+ public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
+ // no-op by design: this jar never stores cookies
+ }
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return url.port() == portB ? List.of(new Cookie.Builder().name("jar").value("b").domain("127.0.0.1").build()) : List.of();
diff --git a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_SsrfGuard_Test.java b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_SsrfGuard_Test.java
index e92044d937..5cb92188b4 100644
--- a/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_SsrfGuard_Test.java
+++ b/juneau-rest/juneau-rest-client-okhttp/src/test/java/org/apache/juneau/rest/client/OkHttpTransport_SsrfGuard_Test.java
@@ -54,7 +54,7 @@ class OkHttpTransport_SsrfGuard_Test {
server.createContext("/hello", exchange -> {
var body = "hi".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, body.length);
- exchange.getResponseBody().write(body);
+ try (var os = exchange.getResponseBody()) { os.write(body); }
exchange.close();
});
server.createContext("/to-numeric", exchange -> {
@@ -77,7 +77,7 @@ class OkHttpTransport_SsrfGuard_Test {
// =================================================================================================================
@Test
- void a01_guarded_freshTransport_rejected() throws Exception {
+ void a01_guarded_freshTransport_rejected() {
try (var transport = OkHttpTransport.create()) {
assertRejectedLoopback(transport);
}
@@ -109,7 +109,7 @@ class OkHttpTransport_SsrfGuard_Test {
// =================================================================================================================
@Test
- void b01_unguarded_unknownHost_transportExceptionWithUnknownHostCause() throws Exception {
+ void b01_unguarded_unknownHost_transportExceptionWithUnknownHostCause() {
var ex = assertThrows(TransportException.class, () -> executeWithDns(host -> { throw new UnknownHostException(host); }));
assertInstanceOf(UnknownHostException.class, ex.getCause());
}
@@ -126,21 +126,21 @@ class OkHttpTransport_SsrfGuard_Test {
// =================================================================================================================
@Test
- void c01_guarded_ipv4LiteralLoopback_rejected() throws Exception {
+ void c01_guarded_ipv4LiteralLoopback_rejected() {
try (var transport = OkHttpTransport.create()) {
assertRejectedLiteral(transport, "http://127.0.0.1:" + server.getAddress().getPort() + "/hello", "127.0.0.1");
}
}
@Test
- void c02_guarded_ipv6LiteralLoopback_rejected() throws Exception {
+ void c02_guarded_ipv6LiteralLoopback_rejected() {
try (var transport = OkHttpTransport.create()) {
assertRejectedLiteral(transport, "http://[::1]:" + server.getAddress().getPort() + "/hello", "::1");
}
}
@Test
- void c03_guarded_ipv4LiteralPrivate_rejectedOnCallerSuppliedClient() throws Exception {
+ void c03_guarded_ipv4LiteralPrivate_rejectedOnCallerSuppliedClient() {
var client = new okhttp3.OkHttpClient.Builder().proxy(Proxy.NO_PROXY).build();
try (var transport = OkHttpTransport.builder().httpClient(client).build()) {
assertRejectedLiteral(transport, "http://10.1.2.3:9/hello", "10.1.2.3");
@@ -166,7 +166,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void c06_guarded_numericHost_rejected() throws Exception {
+ void c06_guarded_numericHost_rejected() {
// OkHttp treats an all-digit host as an IP literal (2130706433 == 127.0.0.1) and connects without consulting Dns.
try (var transport = OkHttpTransport.create()) {
assertRejectedLiteral(transport, "http://2130706433:" + server.getAddress().getPort() + "/hello", "2130706433");
@@ -174,14 +174,17 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void c07_guarded_shortDottedHost_rejected() throws Exception {
+ void c07_guarded_shortDottedHost_rejected() {
try (var transport = OkHttpTransport.create()) {
assertRejectedLiteral(transport, "http://127.1:" + server.getAddress().getPort() + "/hello", "127.1");
}
}
@Test
- void c08_guarded_redirectToNumericHost_rejected() throws Exception {
+ @SuppressWarnings({
+ "resource" // The stubbed Response and ResponseBody are handed to OkHttp's call chain, which closes them.
+ })
+ void c08_guarded_redirectToNumericHost_rejected() {
var target = "http://2130706433:" + server.getAddress().getPort() + "/hello";
// An application interceptor answers hop 0 (a public-looking name) with a redirect, so no network or Dns is needed.
okhttp3.Interceptor redirector = chain -> {
@@ -200,7 +203,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void d06_guarded_underscoreHost_selectorNotConsulted() throws Exception {
+ void d06_guarded_underscoreHost_selectorNotConsulted() {
// java.net.URI parses an underscore host with a null host; OkHttp skips the ProxySelector for it, so must we.
var calls = new AtomicInteger();
var selector = new ProxySelector() {
@@ -220,7 +223,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void c09_guarded_malformedNumericHost_failsClosed() throws Exception {
+ void c09_guarded_malformedNumericHost_failsClosed() {
// Matches OkHttp's IP-literal pattern but is not a valid literal: refused outright, never handed to a resolver.
try (var transport = OkHttpTransport.create()) {
for (var host : List.of("1.2.3.4.5", "127.0.0.1.", "256.1.1.1", "1.2.3.256", "1.2.65536", "4294967296", "010.0.0.1")) {
@@ -251,7 +254,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void d02_guarded_proxySelectorReturnsProxy_rejected() throws Exception {
+ void d02_guarded_proxySelectorReturnsProxy_rejected() {
var selector = new ProxySelector() {
@Override public List<Proxy> select(URI uri) {
return List.of(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 1)));
@@ -267,7 +270,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void d07_guarded_selectorReturnsNullOrEmpty_treatedAsDirect() throws Exception {
+ void d07_guarded_selectorReturnsNullOrEmpty_treatedAsDirect() {
for (var answer : Arrays.<List<Proxy>>asList(null, List.of())) {
var selector = new ProxySelector() {
@Override public List<Proxy> select(URI uri) { return answer; }
@@ -282,7 +285,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void d03_explicitProxy_supportsUrlPolicyFalse() throws Exception {
+ void d03_explicitProxy_supportsUrlPolicyFalse() {
var client = new okhttp3.OkHttpClient.Builder().proxy(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1))).build();
try (var transport = OkHttpTransport.builder().httpClient(client).build()) {
assertFalse(transport.supportsUrlPolicy());
@@ -290,7 +293,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void d04_noProxy_supportsUrlPolicyTrue() throws Exception {
+ void d04_noProxy_supportsUrlPolicyTrue() {
var client = new okhttp3.OkHttpClient.Builder().proxy(Proxy.NO_PROXY).build();
try (var transport = OkHttpTransport.builder().httpClient(client).build()) {
assertTrue(transport.supportsUrlPolicy());
@@ -338,7 +341,7 @@ class OkHttpTransport_SsrfGuard_Test {
}
@Test
- void e02_withRanges_loopbackAndMetadataLiterals_stillRefused() throws Exception {
+ void e02_withRanges_loopbackAndMetadataLiterals_stillRefused() {
try (var transport = OkHttpTransport.create()) {
for (var host : new String[]{"127.0.0.1", "169.254.169.254", "10.1.2.3"}) {
var req = ranged("http://" + host + ":1/x", LAB);
@@ -361,9 +364,9 @@ class OkHttpTransport_SsrfGuard_Test {
}
private static void assertPlainOk(OkHttpTransport transport) throws Exception {
- try (var response = transport.execute(plain())) {
+ try (var response = transport.execute(plain()); var in = response.getBody()) {
assertEquals(200, response.getStatusCode());
- assertEquals("hi", new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8));
+ assertEquals("hi", new String(in.readAllBytes(), StandardCharsets.UTF_8));
}
}
@@ -381,6 +384,9 @@ class OkHttpTransport_SsrfGuard_Test {
}
/** Minimal SOCKS5 endpoint that records the domain name from the CONNECT request, then closes the connection. */
+ @SuppressWarnings({
+ "resource" // The ServerSocket is owned by this class and closed in close().
+ })
private static final class FakeSocksProxy implements Closeable {
private final ServerSocket ss;
private final AtomicReference<String> host = new AtomicReference<>();
@@ -405,17 +411,17 @@ class OkHttpTransport_SsrfGuard_Test {
private void serve() {
try (var s = ss.accept()) {
s.setSoTimeout(2000);
- var in = new DataInputStream(s.getInputStream());
- var out = s.getOutputStream();
- in.readByte(); // version
- in.readFully(new byte[in.readUnsignedByte()]); // methods
- out.write(new byte[]{5, 0});
- out.flush();
- in.readFully(new byte[3]); // ver, cmd, rsv
- if (in.readUnsignedByte() == 3) { // ATYP domain name
- var b = new byte[in.readUnsignedByte()];
- in.readFully(b);
- host.set(new String(b, StandardCharsets.US_ASCII));
+ try (var in = new DataInputStream(s.getInputStream()); var out = s.getOutputStream()) {
+ in.readByte(); // version
+ in.readFully(new byte[in.readUnsignedByte()]); // methods
+ out.write(new byte[]{5, 0});
+ out.flush();
+ in.readFully(new byte[3]); // ver, cmd, rsv
+ if (in.readUnsignedByte() == 3) { // ATYP domain name
+ var b = new byte[in.readUnsignedByte()];
+ in.readFully(b);
+ host.set(new String(b, StandardCharsets.US_ASCII));
+ }
}
} catch (IOException e) {
// Expected when no client connects or the client gives up; nothing was recorded.
diff --git a/juneau-rest/juneau-rest-client/.sonarlint/connectedMode.json b/juneau-rest/juneau-rest-client/.sonarlint/connectedMode.json
new file mode 100644
index 0000000000..76a32b7486
--- /dev/null
+++ b/juneau-rest/juneau-rest-client/.sonarlint/connectedMode.json
@@ -0,0 +1,5 @@
+{
+ "sonarCloudOrganization": "apache",
+ "projectKey": "apache_juneau",
+ "region": "EU"
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects.java
index 83269204c8..1e53eb7bee 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects.java
@@ -160,6 +160,9 @@ public final class PolicyEnforcedRedirects {
return eqic(method, "GET") || eqic(method, "HEAD");
}
+ @SuppressWarnings({
+ "java:S3776" // Redirect method/body/header rewriting rules read best as one linear sequence.
+ })
private static TransportRequest forRedirect(TransportRequest initial, TransportRequest current, URI target, int statusCode, boolean left) throws TransportException {
var preserveMethod = eqic(current.getMethod(), "GET") || eqic(current.getMethod(), "HEAD");
var rewriteToGet = ! preserveMethod && (statusCode == 301 || statusCode == 302 || statusCode == 303);
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/TransportRequest.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/TransportRequest.java
index 8e3edec5c8..6641e8000c 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/TransportRequest.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/TransportRequest.java
@@ -190,7 +190,7 @@ public final class TransportRequest {
* {@link RestClient.Builder#allowAddressRanges(String...)}); they are unioned with the
* {@value RemoteUrlPolicy#ALLOW_ADDRESS_RANGES_PROPERTY} system property.
*
- * @return The allowed ranges. Never <jk>null</jk>; {@link RemoteUrlPolicy.AllowedRanges#NONE} by default.
+ * @return The allowed ranges. Never <jk>null</jk>; {@link org.apache.juneau.http.remote.RemoteUrlPolicy.AllowedRanges#NONE} by default.
*/
public RemoteUrlPolicy.AllowedRanges getAllowedAddressRanges() {
return allowedAddressRanges;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects_Test.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects_Test.java
index 654b952d9d..def1d5f317 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects_Test.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/PolicyEnforcedRedirects_Test.java
@@ -189,7 +189,7 @@ class PolicyEnforcedRedirects_Test {
assertList(headerNames(hops.last()), "Authorization", "Accept");
}
- @Test void a05f_locationWithUserInfo_isRefused() throws Exception {
+ @Test void a05f_locationWithUserInfo_isRefused() {
var ex = assertThrows(TransportException.class, () -> run(request("http://a.example.com/start"), "http://b.example.com/x", "http://user:pw@a.example.com/echo"));
assertTrue(ex.getMessage().contains("user info"), ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/RestClient_AllowAddressRanges_Test.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/RestClient_AllowAddressRanges_Test.java
index 14ce58d893..73b6e2c298 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/RestClient_AllowAddressRanges_Test.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/RestClient_AllowAddressRanges_Test.java
@@ -19,7 +19,6 @@ package org.apache.juneau.rest.client;
import static org.junit.jupiter.api.Assertions.*;
import java.io.*;
-import java.lang.reflect.*;
import java.util.*;
import org.apache.juneau.*;
@@ -59,9 +58,7 @@ class RestClient_AllowAddressRanges_Test extends TestBase {
}
}
- private static Throwable root(Throwable t) {
- return t instanceof UndeclaredThrowableException u && u.getCause() != null ? u.getCause() : t;
- }
+
//------------------------------------------------------------------------------------------------------------------
// a - builder validation
@@ -103,7 +100,8 @@ class RestClient_AllowAddressRanges_Test extends TestBase {
try (var a = RestClient.builder().transport(withOption).allowAddressRanges("198.18.0.0/15").build();
var b = RestClient.builder().transport(without).build()) {
a.remote(Api.class).get("http://198.18.0.5/x");
- var ex = assertThrows(IllegalArgumentException.class, () -> b.remote(Api.class).get("http://198.18.0.5/x"));
+ var api = b.remote(Api.class);
+ var ex = assertThrows(IllegalArgumentException.class, () -> api.get("http://198.18.0.5/x"));
assertTrue(ex.getMessage().contains("denied by default"), ex.getMessage());
assertTrue(without.requests.isEmpty());
assertEquals(1, withOption.requests.size());
@@ -113,8 +111,9 @@ class RestClient_AllowAddressRanges_Test extends TestBase {
@Test void b03_option_neverReopensLoopbackOrMetadataOrOtherRanges() throws Exception {
var transport = new Recording();
try (var client = RestClient.builder().transport(transport).allowAddressRanges("198.18.0.0/15").build()) {
+ var api = client.remote(Api.class);
for (var url : new String[]{"http://127.0.0.1/x", "http://169.254.169.254/latest", "http://10.0.0.1/x", "http://192.0.0.1/x", "http://224.0.0.1/x", "http://localhost/x"}) {
- var ex = assertThrows(IllegalArgumentException.class, () -> client.remote(Api.class).get(url), url);
+ var ex = assertThrows(IllegalArgumentException.class, () -> api.get(url), url);
assertTrue(ex.getMessage().contains("denied by default"), ex.getMessage());
}
assertTrue(transport.requests.isEmpty());
@@ -130,7 +129,8 @@ class RestClient_AllowAddressRanges_Test extends TestBase {
client.remote(Api.class).get("http://192.0.0.5/x");
client.remote(Api.class).get("http://198.18.0.5/x");
assertEquals(2, transport.requests.size());
- assertThrows(IllegalArgumentException.class, () -> client.remote(Api.class).get("http://224.0.0.5/x"));
+ var api = client.remote(Api.class);
+ assertThrows(IllegalArgumentException.class, () -> api.get("http://224.0.0.5/x"));
}
} finally {
if (previous == null)
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicCsvHeader_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicCsvHeader_Test.java
index 9659464bd1..af7373418c 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicCsvHeader_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicCsvHeader_Test.java
@@ -53,7 +53,8 @@ class BasicCsvHeader_Test extends TestBase {
assertEquals(java.util.List.of("a", "b"), h.asList().get());
assertArrayEquals(new String[]{"a", "b"}, h.toArray());
assertEquals(java.util.List.of("a", "b"), h.toList());
- assertThrows(UnsupportedOperationException.class, () -> h.toList().add("c"));
+ var list = h.toList();
+ assertThrows(UnsupportedOperationException.class, () -> list.add("c"));
}
@Test void b02_arrayIsDefensiveCopy() {
@@ -71,7 +72,8 @@ class BasicCsvHeader_Test extends TestBase {
@Test void b04_assertList() {
new BasicCsvHeader(NAME, "a,b").assertList().isSize(2);
- assertThrows(AssertionError.class, () -> new BasicCsvHeader(NAME, "a,b").assertList().isSize(3));
+ var assertion = new BasicCsvHeader(NAME, "a,b").assertList();
+ assertThrows(AssertionError.class, () -> assertion.isSize(3));
}
@Test void c01_contains_fixedValue() {
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicDateHeader_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicDateHeader_Test.java
index f406172f71..49b862e11f 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicDateHeader_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicDateHeader_Test.java
@@ -75,6 +75,8 @@ class BasicDateHeader_Test extends TestBase {
@Test void b02_assertZonedDateTime() {
new BasicDateHeader(NAME, DATE).assertZonedDateTime().is(DATE);
- assertThrows(AssertionError.class, () -> new BasicDateHeader(NAME, DATE).assertZonedDateTime().is(DATE.plusDays(1)));
+ var assertion = new BasicDateHeader(NAME, DATE).assertZonedDateTime();
+ var other = DATE.plusDays(1);
+ assertThrows(AssertionError.class, () -> assertion.is(other));
}
}
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicIntegerHeader_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicIntegerHeader_Test.java
index 978924e0d9..bd673e8126 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicIntegerHeader_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicIntegerHeader_Test.java
@@ -77,7 +77,8 @@ class BasicIntegerHeader_Test extends TestBase {
@Test void b04_assertInteger() {
new BasicIntegerHeader(NAME, "5").assertInteger().is(5);
- assertThrows(AssertionError.class, () -> new BasicIntegerHeader(NAME, "5").assertInteger().is(6));
+ var assertion = new BasicIntegerHeader(NAME, "5").assertInteger();
+ assertThrows(AssertionError.class, () -> assertion.is(6));
}
@Test void b05_wireString_invalid_throws() {
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicLongHeader_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicLongHeader_Test.java
index 2f5159dada..570d27c6e1 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicLongHeader_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/header/BasicLongHeader_Test.java
@@ -77,7 +77,8 @@ class BasicLongHeader_Test extends TestBase {
@Test void b04_assertLong() {
new BasicLongHeader(NAME, "5").assertLong().is(5L);
- assertThrows(AssertionError.class, () -> new BasicLongHeader(NAME, "5").assertLong().is(6L));
+ var assertion = new BasicLongHeader(NAME, "5").assertLong();
+ assertThrows(AssertionError.class, () -> assertion.is(6L));
}
@Test void b05_wireString_invalid_throws() {
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpException_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpException_Test.java
index 78b6cc00e9..32350c601a 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpException_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpException_Test.java
@@ -264,7 +264,7 @@ class BasicHttpException_Test extends TestBase {
@Test void c09_equalsAndHashCode_distinguishContent() {
var x = new BasicHttpException(404).setHeader2("X-A", "1");
assertEquals(x, x);
- assertNotEquals(x, "not an exception");
+ assertNotEquals("not an exception", x);
assertNotEquals(x, new BasicHttpException(404).setHeader2("X-A", "2"));
assertNotEquals(x, new BasicHttpException(500).setHeader2("X-A", "1"));
assertNotEquals(x, new BasicHttpException(404, "other").setHeader2("X-A", "1"));
@@ -278,7 +278,8 @@ class BasicHttpException_Test extends TestBase {
assertThrows(UnsupportedOperationException.class, () -> u.setParams(null));
assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(org.apache.http.HttpVersion.HTTP_1_1, 200));
assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(org.apache.http.HttpVersion.HTTP_1_1, 200, "OK"));
- assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(new org.apache.http.message.BasicStatusLine(org.apache.http.HttpVersion.HTTP_1_1, 200, "OK")));
+ var statusLine = new org.apache.http.message.BasicStatusLine(org.apache.http.HttpVersion.HTTP_1_1, 200, "OK");
+ assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(statusLine));
assertEquals("1", u.getFirstHeader("X-A").getValue());
}
}
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpResponse_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpResponse_Test.java
index 67728379c1..d9997ffe5b 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpResponse_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/BasicHttpResponse_Test.java
@@ -210,7 +210,7 @@ class BasicHttpResponse_Test extends TestBase {
@Test void c06_equalsAndHashCode_distinguishContent() {
var x = new Ok().setHeader2("X-A", "1").setContent("body");
assertEquals(x, x);
- assertNotEquals(x, "not a response");
+ assertNotEquals("not a response", x);
assertNotEquals(x, new Ok().setHeader2("X-A", "2").setContent("body"));
assertNotEquals(x, new Ok().setHeader2("X-A", "1").setContent("other"));
assertNotEquals(x, new Created().setHeader2("X-A", "1").setContent("body"));
@@ -227,6 +227,7 @@ class BasicHttpResponse_Test extends TestBase {
assertThrows(UnsupportedOperationException.class, () -> u.setLocation("http://localhost/x"));
assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(HttpVersion.HTTP_1_1, 200));
assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(HttpVersion.HTTP_1_1, 200, "OK"));
- assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(new org.apache.http.message.BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK")));
+ var statusLine = new org.apache.http.message.BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK");
+ assertThrows(UnsupportedOperationException.class, () -> u.setStatusLine(statusLine));
}
}
diff --git a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/ClassicResponse_Test.java b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/ClassicResponse_Test.java
index b7ebc26404..937ec8ab17 100644
--- a/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/ClassicResponse_Test.java
+++ b/juneau-rest/juneau-rest-common-classic/src/test/java/org/apache/juneau/http/classic/response/ClassicResponse_Test.java
@@ -263,19 +263,19 @@ class ClassicResponse_Test extends TestBase {
@ParameterizedTest
@MethodSource("a06_exceptionClasses")
- void b01_exceptionFluentSetters(Class<? extends BasicHttpException> type, int expectedCode, String expectedPhrase) throws Exception {
+ void b01_exceptionFluentSetters(Class<? extends BasicHttpException> type) throws Exception {
var methods = fluentMethods(type);
assertTrue(methods.size() >= 10, type::getName);
for (var m : methods) {
var instance = type.getDeclaredConstructor().newInstance().setHeader2("Pre", "1").setReasonPhrase2("Custom");
var args = sampleArgs(m);
assertSame(instance, m.invoke(instance, args), m::getName);
- assertSetterState(instance, m, args, expectedCode, expectedPhrase);
+ assertSetterState(instance, m, args);
}
}
/** Asserts the observable state change each fluent setter promises (sample args come from {@link #sampleArg}). */
- private static void assertSetterState(BasicHttpException x, Method m, Object[] a, int expectedCode, String expectedPhrase) throws Exception {
+ private static void assertSetterState(BasicHttpException x, Method m, Object[] a) throws Exception {
Supplier<String> what = m::toString;
switch (m.getName()) {
case "setContent" -> {
@@ -345,7 +345,7 @@ class ClassicResponse_Test extends TestBase {
@ParameterizedTest
@MethodSource("a06_exceptionClasses")
- void b04b_exceptionResponseConstructorRejectsMismatchedStatus(Class<? extends BasicHttpException> type, int expectedCode, String expectedPhrase) throws Exception {
+ void b04b_exceptionResponseConstructorRejectsMismatchedStatus(Class<? extends BasicHttpException> type, int expectedCode, String expectedPhrase) {
var ex = assertThrows(InvocationTargetException.class, () -> type.getConstructor(HttpResponse.class).newInstance(new BasicHttpException(599)));
assertInstanceOf(IllegalArgumentException.class, ex.getCause());
assertTrue(ex.getCause().getMessage().contains("Expected:[" + expectedCode + "], Actual:[599]"), ex.getCause().getMessage());
@@ -353,7 +353,7 @@ class ClassicResponse_Test extends TestBase {
@ParameterizedTest
@MethodSource("a01_responseClasses")
- void b05b_responseResponseConstructorRejectsMismatchedStatus(Class<? extends BasicHttpResponse<?>> type, int expectedCode, String expectedPhrase) throws Exception {
+ void b05b_responseResponseConstructorRejectsMismatchedStatus(Class<? extends BasicHttpResponse<?>> type, int expectedCode, String expectedPhrase) {
var ex = assertThrows(InvocationTargetException.class, () -> type.getConstructor(HttpResponse.class).newInstance(new BasicHttpException(599)));
assertInstanceOf(IllegalArgumentException.class, ex.getCause());
assertTrue(ex.getCause().getMessage().contains("Expected:[" + expectedCode + "], Actual:[599]"), ex.getCause().getMessage());
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/remote/RemoteUrlPolicy.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/remote/RemoteUrlPolicy.java
index bd816af828..19c10f7cae 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/remote/RemoteUrlPolicy.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/remote/RemoteUrlPolicy.java
@@ -20,7 +20,9 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import java.net.*;
import java.util.*;
+import java.util.concurrent.atomic.*;
import java.util.regex.*;
+import java.util.stream.*;
/**
* Shared SSRF-hardening policy for the {@link Remote @Remote}/{@link RemoteOp @RemoteOp} proxy engines.
@@ -313,6 +315,21 @@ public final class RemoteUrlPolicy {
/** A parsed CIDR range. */
private record Cidr(byte[] prefix, int bits) {
+ @Override /* Object */
+ public boolean equals(Object o) {
+ return o instanceof Cidr other && bits == other.bits && Arrays.equals(prefix, other.prefix);
+ }
+
+ @Override /* Object */
+ public int hashCode() {
+ return 31 * Arrays.hashCode(prefix) + bits;
+ }
+
+ @Override /* Object */
+ public String toString() {
+ return "Cidr[prefix=" + Arrays.toString(prefix) + ", bits=" + bits + "]";
+ }
+
boolean contains(byte[] b) {
if (b.length != prefix.length)
return false;
@@ -346,10 +363,7 @@ public final class RemoteUrlPolicy {
private AllowedRanges(List<Cidr> ranges) {
this.ranges = ranges;
- var k = new TreeSet<String>();
- for (var r : ranges)
- k.add(Arrays.toString(r.prefix()) + "/" + r.bits());
- this.key = k;
+ this.key = ranges.stream().map(r -> Arrays.toString(r.prefix()) + "/" + r.bits()).collect(Collectors.toCollection(TreeSet::new));
}
/**
@@ -400,11 +414,7 @@ public final class RemoteUrlPolicy {
// Parses a spec without touching the single-entry property cache; an invalid entry throws.
private static List<Cidr> parseAllowedRangesStrict(String spec) {
- var list = new ArrayList<Cidr>();
- for (var token : spec.trim().split("[,\\s]+"))
- if (! token.isEmpty())
- list.add(parseAllowEntry(token));
- return list;
+ return Arrays.stream(spec.trim().split("[,\\s]+")).filter(token -> ! token.isEmpty()).map(RemoteUrlPolicy::parseAllowEntry).toList();
}
// The only ranges the allow-list may re-permit (and that every allow entry must lie within).
@@ -416,19 +426,21 @@ public final class RemoteUrlPolicy {
new Cidr(new byte[]{(byte)0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8)
);
- private static final Pattern ALLOW_ENTRY = Pattern.compile("^([0-9.]+|[0-9A-Fa-f:.]*:[0-9A-Fa-f:.]*)(?:/(0|[1-9][0-9]{0,2}))?$");
+ private static final Pattern ALLOW_ENTRY = Pattern.compile("^([\\d.]+|[\\dA-Fa-f.]*:[\\dA-Fa-f:.]*)(?:/(0|[1-9]\\d{0,2}))?$");
// Single-entry cache (successes and failures): the spec is normally a constant system property, so parse once per
// distinct value. A failed parse is remembered by message so the same string throws again without re-parsing.
private record ParsedAllow(String spec, List<Cidr> ranges, String error) {}
- private static volatile ParsedAllow parsedAllow = new ParsedAllow("", List.of(), null);
+ private static final AtomicReference<ParsedAllow> PARSED_ALLOW = new AtomicReference<>(new ParsedAllow("", List.of(), null));
private static List<Cidr> parseAllowedRanges(String spec) {
if (spec == null || spec.isBlank())
return List.of();
- var cached = parsedAllow;
- if (! cached.spec().equals(spec))
- cached = parsedAllow = parseAllowSpec(spec);
+ var cached = PARSED_ALLOW.get();
+ if (! cached.spec().equals(spec)) {
+ cached = parseAllowSpec(spec);
+ PARSED_ALLOW.set(cached);
+ }
if (cached.error() != null)
throw iaex("%s", cached.error());
return cached.ranges();
@@ -443,6 +455,9 @@ public final class RemoteUrlPolicy {
}
// Parses a dotted-quad IPv4 literal purely syntactically (octets 0-255, no leading zeros); returns null if invalid.
+ @SuppressWarnings({
+ "java:S1168" // null signals an invalid IPv4 literal (see comment); callers test for it
+ })
private static byte[] parseIpv4(String s) {
var parts = s.split("\\.", -1);
if (parts.length != 4)
@@ -450,7 +465,7 @@ public final class RemoteUrlPolicy {
var out = new byte[4];
for (var i = 0; i < 4; i++) {
var p = parts[i];
- if (! (p.equals("0") || p.matches("[1-9][0-9]{0,2}")))
+ if (! (p.equals("0") || p.matches("[1-9]\\d{0,2}")))
return null;
var v = Integer.parseInt(p);
if (v > 255)
@@ -541,6 +556,9 @@ public final class RemoteUrlPolicy {
* Unwraps an IPv6 address that embeds an IPv4 address (IPv4-mapped, IPv4-compatible, IPv4-translated, NAT64
* or 6to4) to the embedded {@link Inet4Address}; any other address is returned unchanged.
*/
+ @SuppressWarnings({
+ "java:S3776" // One flat decision table over the IPv6 embedding prefixes; splitting it would scatter the byte-layout rules.
+ })
private static InetAddress unwrapEmbeddedIpv4(InetAddress addr) {
if (! (addr instanceof Inet6Address))
return addr;
diff --git a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
index dde80bfc44..23b2ea1a8c 100644
--- a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
@@ -305,7 +305,7 @@ public final class MockRestClient implements Closeable {
var overlay = overridingBeanStore;
// Only class-based contexts are cached; a caller-supplied instance always gets its own context.
var cacheable = isClass && overlay == null;
- RestContext restContext = cacheable ? restContextCache.get((Class<?>)impl) : null;
+ RestContext restContext = cacheable ? restContextCache.get(impl) : null;
if (restContext == null) {
var o = isClass ? ((Class<?>)impl).getDeclaredConstructor().newInstance() : impl;
restContext = new RestContext(new RestContext.Args(o.getClass(), null, null, () -> o, "", bs -> {
diff --git a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockRestClient.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockRestClient.java
index 514db609da..00d4ed5b5b 100644
--- a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockRestClient.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockRestClient.java
@@ -609,7 +609,7 @@ public class MockRestClient extends RestClient implements HttpClientConnection {
var isClass = restBean instanceof Class;
// Only class-based contexts are cached; a caller-supplied instance always gets its own context.
var cacheable = isClass && overlay == null;
- var restBeanCtx = cacheable ? restContexts.get((Class<?>)restBean) : null;
+ var restBeanCtx = cacheable ? restContexts.get(restBean) : null;
if (restBeanCtx == null) {
var o = isClass ? ((Class<?>)restBean).getDeclaredConstructor().newInstance() : restBean;
restBeanCtx = new RestContext(new RestContext.Args(o.getClass(), null, null, () -> o, "", bs -> {
diff --git a/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/NoTrace_Test.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/NoTrace_Test.java
index 28a4288954..91f56dab7f 100644
--- a/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/NoTrace_Test.java
+++ b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/NoTrace_Test.java
@@ -25,6 +25,8 @@ import org.apache.juneau.http.*;
import org.apache.juneau.http.response.*;
import org.apache.juneau.rest.server.*;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
/**
* Verifies that the <c>No-Trace</c> request header and the <js>"NoTrace"</js> request attribute keep the stack trace off
@@ -84,9 +86,15 @@ class NoTrace_Test {
}
}
- @Test void a01_withoutNoTrace_recordCarriesThrown() {
+ @ParameterizedTest
+ @CsvSource({
+ "/bad?n=abc, false", // No No-Trace anywhere.
+ "/failPlain, false", // Exception set with no NoTrace attribute.
+ "/failAttrFalse, true" // The attribute (false) wins over the header (true).
+ })
+ void a01_recordCarriesThrown(String path, boolean noTrace) {
var client = MockRestClient.create(A_Resource.class);
- var rec = capture(c -> run(c, "/bad?n=abc", false), client);
+ var rec = capture(c -> run(c, path, noTrace), client);
assertNotNull(rec.getThrown());
}
@@ -115,12 +123,6 @@ class NoTrace_Test {
assertNotNull(rec.getThrown());
}
- @Test void a05a_noAttribute_recordCarriesThrown() {
- var client = MockRestClient.create(A_Resource.class);
- var rec = capture(c -> run(c, "/failPlain", false), client);
- assertNotNull(rec.getThrown());
- }
-
@Test void a05_requestAttribute_suppressesThrown() {
var client = MockRestClient.create(A_Resource.class);
var rec = capture(c -> run(c, "/failAttr", false), client);
@@ -133,10 +135,4 @@ class NoTrace_Test {
var rec = capture(c -> run(c, "/bad?n=abc", false), client);
assertNotNull(rec.getThrown());
}
-
- @Test void a07_attributeFalse_winsOverHeaderTrue_keepsThrown() {
- var client = MockRestClient.create(A_Resource.class);
- var rec = capture(c -> run(c, "/failAttrFalse", true), client);
- assertNotNull(rec.getThrown());
- }
}
diff --git a/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/RestDebugFinishContainment_Test.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/RestDebugFinishContainment_Test.java
index 33fb1d3573..3acbe50de5 100644
--- a/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/RestDebugFinishContainment_Test.java
+++ b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/mock/RestDebugFinishContainment_Test.java
@@ -54,7 +54,7 @@ class RestDebugFinishContainment_Test {
}
}
- @Test void a01_formatterThrowsRuntimeAtFinest_requestStillCompletes_fixedTokenOnly() throws Exception {
+ @Test void a01_formatterThrowsRuntimeAtFinest_requestStillCompletes_fixedTokenOnly() {
var records = LogRecordCapture.quietly(FINISH_LOGGER, () -> LogRecordCapture.quietly(org.apache.juneau.rest.client.classic.RestClient.class, () -> {
var client = org.apache.juneau.rest.mock.classic.MockRestClient.create(A_ThrowsRuntimeInBody.class).debug().build();
diff --git a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Metadata_Test.java b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Metadata_Test.java
index bdc851e65a..58a4d0be05 100644
--- a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Metadata_Test.java
+++ b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Metadata_Test.java
@@ -27,7 +27,6 @@ import org.apache.juneau.*;
import org.apache.juneau.rest.server.auth.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.*;
-import org.opensaml.security.credential.*;
/**
* End-to-end tests for {@link SamlAssertionValidator} resolving the IdP signing certificate from real SAML
@@ -91,14 +90,16 @@ class SamlAssertionValidator_Metadata_Test extends TestBase {
// The trust-anchor certificate is rejected outside its validity window, so no signing credential remains.
var early = Clock.fixed(Instant.parse("2020-01-01T00:00:00Z"), ZoneOffset.UTC);
var v = validator(metadata(certElement(SamlTestKeys.CERT_BASE64)), early);
- var ex = assertThrows(AuthenticationException.class, () -> v.validate(signedResponse()));
+ var xml = signedResponse();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("No signing X.509 certificate"), ex.getMessage());
}
@Test void a04_certificateExpired_rejected() throws Exception {
var late = Clock.fixed(Instant.parse("2130-01-01T00:00:00Z"), ZoneOffset.UTC);
var v = validator(metadata(certElement(SamlTestKeys.CERT_BASE64)), late);
- var ex = assertThrows(AuthenticationException.class, () -> v.validate(signedResponse()));
+ var xml = signedResponse();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("No signing X.509 certificate"), ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Rejections_Test.java b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Rejections_Test.java
index af81d7a3a5..e259905b82 100644
--- a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Rejections_Test.java
+++ b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlAssertionValidator_Rejections_Test.java
@@ -77,18 +77,23 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
@Test void a01_statusNotSuccess_rejected() throws Exception {
var xml = response("<samlp:Status><samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Responder\"/></samlp:Status>");
- var ex = assertThrows(AuthenticationException.class, () -> base(cred()).build().validate(xml));
+ var v = base(cred()).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("not Success"), ex.getMessage());
assertTrue(challenge(ex).contains("invalid_response"));
}
@Test void a02_noStatusElement_rejected() throws Exception {
- var ex = assertThrows(AuthenticationException.class, () -> base(cred()).build().validate(response("")));
+ var xml = response("");
+ var v = base(cred()).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("not Success"), ex.getMessage());
}
@Test void a03_statusWithoutStatusCode_rejected() throws Exception {
- var ex = assertThrows(AuthenticationException.class, () -> base(cred()).build().validate(response("<samlp:Status/>")));
+ var xml = response("<samlp:Status/>");
+ var v = base(cred()).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("not Success"), ex.getMessage());
}
@@ -99,14 +104,16 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
@Test void b01_signatureWithoutSignatureMethod_rejectedAtParse() throws Exception {
var cred = cred();
var xml = signed(cred).replaceAll("<(\\w+:)?SignatureMethod[^>]*/>", "");
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("could not be parsed"), ex.getMessage());
}
@Test void b02_sha1ReferenceDigest_rejected() throws Exception {
var cred = cred();
var xml = signed(cred).replace(SignatureConstants.ALGO_ID_DIGEST_SHA256, SignatureConstants.ALGO_ID_DIGEST_SHA1);
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("digest algorithm not allowlisted"), ex.getMessage());
assertTrue(challenge(ex).contains("signature_algorithm_rejected"));
}
@@ -114,7 +121,8 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
@Test void b03_emptyReferenceDigest_rejected() throws Exception {
var cred = cred();
var xml = signed(cred).replace("Algorithm=\"" + SignatureConstants.ALGO_ID_DIGEST_SHA256 + "\"", "Algorithm=\"\"");
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("digest algorithm not allowlisted"), ex.getMessage());
}
@@ -136,7 +144,8 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
@Test void b06_referenceNotPointingAtAssertion_profileValidationFails() throws Exception {
var cred = cred();
var xml = signed(cred).replaceAll("<(\\w+:)?Reference URI=\"#[^\"]*\"", "<ds:Reference URI=\"#_other\"");
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("signature profile validation failed"), ex.getMessage());
assertTrue(challenge(ex).contains("signature_invalid"));
}
@@ -182,21 +191,24 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
var sc = scb.buildObject();
sc.setMethod(SubjectConfirmation.METHOD_BEARER);
var xml = signedWithConfirmation(cred, sc);
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml, ACS));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml, ACS));
assertTrue(ex.getMessage().contains("SubjectConfirmationData> is missing"), ex.getMessage());
}
@Test void d02_confirmationNotYetValid_rejected() throws Exception {
var cred = cred();
var xml = signedWithConfirmation(cred, SamlTestSupport.bearerConfirmation(ACS, NOW.plusSeconds(600), NOA, null, null));
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml, ACS));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml, ACS));
assertTrue(ex.getMessage().contains("not yet valid"), ex.getMessage());
}
@Test void d03_unsolicitedConfirmationWithInResponseTo_rejected() throws Exception {
var cred = cred();
var xml = signedWithConfirmation(cred, SamlTestSupport.bearerConfirmation(ACS, null, NOA, "_req1", null));
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml, ACS));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml, ACS));
assertTrue(ex.getMessage().contains("unsolicited"), ex.getMessage());
}
@@ -215,7 +227,8 @@ class SamlAssertionValidator_Rejections_Test extends TestBase {
var assertion = SamlTestSupport.buildMinimalAssertion(ISSUER, AUDIENCE, "alice", NBF, NOA);
assertion.setID(null);
var xml = SamlTestSupport.signAndBuildResponse(cred, ISSUER, assertion);
- var ex = assertThrows(AuthenticationException.class, () -> base(cred).build().validate(xml));
+ var v = base(cred).build();
+ var ex = assertThrows(AuthenticationException.class, () -> v.validate(xml));
assertTrue(ex.getMessage().contains("no ID"), ex.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlMetadataResolvers_Signed_Test.java b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlMetadataResolvers_Signed_Test.java
index 2c06e53deb..2b1b9f6070 100644
--- a/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlMetadataResolvers_Signed_Test.java
+++ b/juneau-rest/juneau-rest-server-auth-saml/src/test/java/org/apache/juneau/rest/server/auth/saml/SamlMetadataResolvers_Signed_Test.java
@@ -155,9 +155,10 @@ class SamlMetadataResolvers_Signed_Test extends TestBase {
@Test void b03_connectionClosedMidBody_throwsIOException() throws Exception {
withServer(exchange -> {
exchange.sendResponseHeaders(200, 100_000); // promise far more bytes than are sent
- var os = exchange.getResponseBody();
- os.write(new byte[16]);
- os.flush();
+ try (var os = exchange.getResponseBody()) {
+ os.write(new byte[16]);
+ os.flush();
+ }
exchange.close();
}, url -> assertThrows(IOException.class, () -> SamlMetadataResolvers.url(url)));
}
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator.java b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator.java
index 4ba3143989..12992211da 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator.java
@@ -54,7 +54,7 @@ import jakarta.websocket.server.*;
* map across handshakes would mix up concurrent connections.
*
* <p>
- * With {@link CsrfBoundary.Builder#trustedProxies(String...) trustedProxies} set, the handshake's peer is read from the
+ * With {@link org.apache.juneau.rest.server.filter.CsrfBoundary.Builder#trustedProxies(String...) trustedProxies} set, the handshake's peer is read from the
* Jetty user property {@code jakarta.websocket.endpoint.remoteAddress}. Jakarta WebSocket has no standard peer
* address; a container that records none (Tomcat) leaves the peer unknown, and an unknown peer is not trusted, so a
* handshake that carries a forwarded host is refused there. The property is believable only because Jetty writes it
@@ -141,6 +141,9 @@ public final class BusWebSocketConfigurator extends ServerEndpointConfig.Configu
props.put(REFUSAL_PROPERTY, refusal);
}
+ @SuppressWarnings({
+ "java:S3776" // Handshake gate: boundary variants and session lookup read best as one sequential check
+ })
private Refusal check(HandshakeRequest request, Map<String,Object> props) {
var uri = request.getRequestURI();
if (csrf != null) {
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint.java b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint.java
index 018ceb730b..4e7f44196c 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint.java
@@ -19,6 +19,7 @@ package org.apache.juneau.rest.server.bus.websocket;
import static java.nio.charset.StandardCharsets.*;
import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
import java.util.logging.*;
import org.apache.juneau.rest.server.bus.*;
@@ -54,8 +55,8 @@ public final class BusWebSocketEndpoint extends Endpoint {
private final ServerBus bus;
private final Executor closer;
- private volatile BusSession busSession;
- private volatile WsFrameSink sink;
+ private final AtomicReference<BusSession> busSession = new AtomicReference<>();
+ private final AtomicReference<WsFrameSink> sink = new AtomicReference<>();
BusWebSocketEndpoint(ServerBus bus) {
this(bus, null);
@@ -83,8 +84,8 @@ public final class BusWebSocketEndpoint extends Endpoint {
var maxBytes = policy.maxFrameBytes();
session.setMaxTextMessageBufferSize(maxBytes);
var k = closer == null ? new WsFrameSink(session, policy.maxQueuedFrames()) : new WsFrameSink(session, policy.maxQueuedFrames(), closer);
- busSession = s;
- sink = k;
+ busSession.set(s);
+ sink.set(k);
try {
bus.connect(s, k);
} catch (RuntimeException e) {
@@ -112,10 +113,10 @@ public final class BusWebSocketEndpoint extends Endpoint {
@Override /* Endpoint */
public void onClose(Session session, CloseReason closeReason) {
- var k = sink;
+ var k = sink.get();
if (k != null) {
k.markClosed();
- bus.disconnect(busSession, k);
+ bus.disconnect(busSession.get(), k);
}
}
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets.java b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets.java
index fea2159b9d..8cfaf120fc 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets.java
@@ -50,9 +50,15 @@ import jakarta.websocket.server.*;
public final class BusWebSockets {
/** The context-relative endpoint path. */
+ @SuppressWarnings({
+ "java:S1075" // Documented default endpoint path; public constant
+ })
public static final String PATH = "/juneau-bus/ws/{sessionId}";
/** {@link #PATH} without its path parameter; passed to {@link ServerBus#enableWebSocket(String)}. */
+ @SuppressWarnings({
+ "java:S1075" // Documented default endpoint path; public constant
+ })
public static final String PREFIX = "/juneau-bus/ws";
static final String NO_CONTAINER = "BusWebSockets.register: the container exposes no jakarta.websocket ServerContainer (add the container's WebSocket module)";
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink.java b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink.java
index a1d7faa33c..b5be551184 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/main/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink.java
@@ -44,7 +44,7 @@ final class WsFrameSink implements FrameSink {
* undeployed web application is not pinned. Core equals max because a {@link ThreadPoolExecutor} with an
* unbounded queue never grows past its core size.
*/
- private static final Executor CLOSER = closerPool();
+ private static final Executor DEFAULT_CLOSER = closerPool();
private static Executor closerPool() {
var pool = new ThreadPoolExecutor(8, 8, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), r -> {
@@ -61,12 +61,13 @@ final class WsFrameSink implements FrameSink {
private final int maxQueued;
private final Executor closer;
private final ArrayDeque<String> queue = new ArrayDeque<>();
- private boolean sending, closed;
+ private boolean sending;
+ private boolean closed;
private Thread pumpThread;
private String pending;
WsFrameSink(Session session, int maxQueued) {
- this(session, maxQueued, CLOSER);
+ this(session, maxQueued, DEFAULT_CLOSER);
}
WsFrameSink(Session session, int maxQueued, Executor closer) {
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusFixture.java b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusFixture.java
index 2f9a4abe60..f0bbe34442 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusFixture.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusFixture.java
@@ -19,7 +19,6 @@ package org.apache.juneau.rest.server.bus.websocket;
import java.security.*;
import java.util.*;
-import org.apache.juneau.*;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.marshall.json.JsonParser;
import org.apache.juneau.marshall.marshaller.*;
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator_Test.java b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator_Test.java
index 921ee9ed2e..f7e2b41f43 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator_Test.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketConfigurator_Test.java
@@ -732,7 +732,7 @@ class BusWebSocketConfigurator_Test extends TestBase {
verify(ws).close(reason.capture());
verify(ws, never()).getAsyncRemote();
verify(ws, never()).getBasicRemote();
- verify(ws, never()).addMessageHandler(eq(String.class), any(MessageHandler.Whole.class));
+ verify(ws, never()).addMessageHandler(eq(String.class), org.mockito.ArgumentMatchers.<MessageHandler.Whole<String>>any());
return reason.getValue().getCloseCode().getCode();
}
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint_Test.java b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint_Test.java
index 637e15240d..8ddf8cc3fe 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint_Test.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSocketEndpoint_Test.java
@@ -276,8 +276,8 @@ class BusWebSocketEndpoint_Test extends TestBase {
var log = java.util.logging.Logger.getLogger(BusWebSocketEndpoint.class.getName());
var handler = new java.util.logging.Handler() {
@Override public void publish(java.util.logging.LogRecord r) { records.add(r); }
- @Override public void flush() {}
- @Override public void close() {}
+ @Override public void flush() { /* nothing buffered */ }
+ @Override public void close() { /* nothing to release */ }
};
var old = log.getLevel();
log.setLevel(java.util.logging.Level.ALL);
@@ -306,7 +306,7 @@ class BusWebSocketEndpoint_Test extends TestBase {
@Test void e01_theMessageHandlerIsRegisteredAfterTheBusConnects() {
var handlerAtFirstSend = new boolean[] {false};
var added = new boolean[] {false};
- doAnswer(i -> { added[0] = true; return null; }).when(ws).addMessageHandler(eq(String.class), any(MessageHandler.Whole.class));
+ doAnswer(i -> { added[0] = true; return null; }).when(ws).addMessageHandler(eq(String.class), ArgumentMatchers.<MessageHandler.Whole<String>>any());
doAnswer(i -> {
if (sent.isEmpty())
handlerAtFirstSend[0] = added[0];
@@ -325,8 +325,8 @@ class BusWebSocketEndpoint_Test extends TestBase {
var log = java.util.logging.Logger.getLogger(BusWebSocketEndpoint.class.getName());
var handler = new java.util.logging.Handler() {
@Override public void publish(java.util.logging.LogRecord r) { records.add(r); }
- @Override public void flush() {}
- @Override public void close() {}
+ @Override public void flush() { /* nothing buffered */ }
+ @Override public void close() { /* nothing to release */ }
};
var useParent = log.getUseParentHandlers();
log.setUseParentHandlers(false); // the expected warning stays out of the test output
@@ -342,6 +342,6 @@ class BusWebSocketEndpoint_Test extends TestBase {
var r = closedWith();
assertEquals(1011, r.getCloseCode().getCode());
assertEquals("bus:connect-failed", r.getReasonPhrase());
- verify(ws, never()).addMessageHandler(eq(String.class), any(MessageHandler.Whole.class));
+ verify(ws, never()).addMessageHandler(eq(String.class), ArgumentMatchers.<MessageHandler.Whole<String>>any());
}
}
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets_Test.java b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets_Test.java
index c352de517e..97f0090357 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets_Test.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/BusWebSockets_Test.java
@@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
-import java.security.*;
import java.util.*;
import org.apache.juneau.*;
@@ -35,6 +34,9 @@ import jakarta.websocket.*;
import jakarta.websocket.server.*;
/** {@link BusWebSockets#register}: the missing-container and missing-Origin-rule errors in both forms, the endpoint config, and {@link ServerBus#enableWebSocket}. */
+@SuppressWarnings({
+ "java:S3415" // Expected value is already first; Sonar mistakes the computed or constant value for the actual value
+})
class BusWebSockets_Test extends TestBase {
private ServerBus bus;
diff --git a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink_Test.java b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink_Test.java
index 86b2107180..69b3127fa0 100644
--- a/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink_Test.java
+++ b/juneau-rest/juneau-rest-server-bus-websocket/src/test/java/org/apache/juneau/rest/server/bus/websocket/WsFrameSink_Test.java
@@ -194,7 +194,7 @@ class WsFrameSink_Test extends TestBase {
assertEquals("after", order.get(1001));
}
- @Test void e02_aFailedSendAfterAClose_doesNotCloseAgain() throws Exception {
+ @Test void e02_aFailedSendAfterAClose_doesNotCloseAgain() {
sink.offer("f1");
var h = sentHandler("f1");
sink.close(1001, "bus:closed");
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusFrames.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusFrames.java
index d50dcead1f..4ea89932a2 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusFrames.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusFrames.java
@@ -41,6 +41,11 @@ import org.apache.juneau.marshall.marshaller.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S127", // utf8Length() and quote() skip the low surrogate of a pair inside the loop body.
+ "java:S1192", // Frame field names and types are wire-format literals; named constants would not clarify them.
+ "java:S3776" // Branching is inherent to decode() and isSingleObject().
+})
public final class BusFrames {
/** The wire format version. */
@@ -221,7 +226,8 @@ public final class BusFrames {
*/
public static int utf8Length(String s) {
var n = 0;
- for (var i = 0; i < s.length(); i++) {
+ var i = 0;
+ while (i < s.length()) {
var c = s.charAt(i);
if (c < 0x80)
n++;
@@ -232,6 +238,7 @@ public final class BusFrames {
i++;
} else
n += 3;
+ i++;
}
return n;
}
@@ -245,7 +252,8 @@ public final class BusFrames {
*/
static String quote(String s) {
var sb = new StringBuilder(s.length() + 2).append('"');
- for (var i = 0; i < s.length(); i++) {
+ var i = 0;
+ while (i < s.length()) {
var c = s.charAt(i);
switch (c) {
case '"' -> sb.append("\\\"");
@@ -267,6 +275,7 @@ public final class BusFrames {
sb.append(c);
}
}
+ i++;
}
return sb.append('"').toString();
}
@@ -292,13 +301,11 @@ public final class BusFrames {
i++;
} else if (c == '{' || c == '[') {
depth++;
- } else if (c == '}' || c == ']') {
- if (--depth == 0) {
- for (i++; i < n; i++)
- if (! isWhitespace(text.charAt(i)))
- return false;
- return true;
- }
+ } else if ((c == '}' || c == ']') && --depth == 0) {
+ for (i++; i < n; i++)
+ if (! isWhitespace(text.charAt(i)))
+ return false;
+ return true;
}
}
return false;
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusPolicy.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusPolicy.java
index 0e14348f7b..9bf30ebd93 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusPolicy.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusPolicy.java
@@ -153,6 +153,9 @@ public final class BusPolicy {
* @param contract The page contract (for example {@code PageCapture.of(html).contract()}).
* @throws IllegalStateException Listing every denied topic, one {@code E-55} line each.
*/
+ @SuppressWarnings({
+ "java:S3776" // Walking the bridge contract is inherently nested.
+ })
public void check(Map<String,?> contract) {
var problems = new ArrayList<String>();
if (contract != null && contract.get("bridges") instanceof Collection<?> bridges) {
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusStream.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusStream.java
index 4f4b237e36..82cbeda11e 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusStream.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/BusStream.java
@@ -86,6 +86,8 @@ final class BusStream {
* @return The path, or {@code ""} for a root servlet in a root context.
*/
static String trimBase(String path) {
- return path == null || path.equals("/") ? "" : path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
+ if (path == null || path.equals("/"))
+ return "";
+ return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
}
}
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/ServerBus.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/ServerBus.java
index 3255defeba..597a777466 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/ServerBus.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/ServerBus.java
@@ -23,6 +23,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.*;
+import java.util.stream.*;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.marshall.marshaller.*;
@@ -59,6 +60,10 @@ import jakarta.servlet.http.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Transport names and refusal reasons are protocol literals; named constants would not clarify them.
+ "java:S3776" // Branching is inherent to openSession() and receive().
+})
public final class ServerBus implements AutoCloseable {
private static final Logger LOGGER = Logger.getLogger(ServerBus.class.getName());
@@ -280,13 +285,10 @@ public final class ServerBus implements AutoCloseable {
throw BusRefusal.transportUnavailable();
var authorizer = policy.authorizer();
- var denied = new ArrayList<String>();
- for (var x : downstream)
- if (policy.downstreamRetain(x).isEmpty() || ! authorizer.test(req, x))
- denied.add(x);
- for (var x : upstream)
- if (! policy.allowsUpstream(x) || ! authorizer.test(req, x))
- denied.add(x);
+ var denied = Stream.concat(
+ downstream.stream().filter(x -> policy.downstreamRetain(x).isEmpty() || ! authorizer.test(req, x)),
+ upstream.stream().filter(x -> ! policy.allowsUpstream(x) || ! authorizer.test(req, x))
+ ).toList();
if (! denied.isEmpty())
throw BusRefusal.topicDenied(echoable(denied));
@@ -360,8 +362,7 @@ public final class ServerBus implements AutoCloseable {
sink.close(4401, "bus:unknown-session");
return;
}
- var old = s.sink;
- s.sink = sink;
+ var old = s.sink.getAndSet(sink);
s.lastSent = clock.instant();
if (old != null)
old.close(4409, "bus:replaced");
@@ -386,8 +387,8 @@ public final class ServerBus implements AutoCloseable {
public void disconnect(BusSession session, FrameSink sink) {
var s = impl(session);
synchronized (lock) {
- if (sink != null && s.sink == sink) {
- s.sink = null;
+ if (sink != null && s.sink.get() == sink) {
+ s.sink.set(null);
s.disconnectedAt = clock.instant();
}
}
@@ -504,9 +505,7 @@ public final class ServerBus implements AutoCloseable {
*/
JsonMap grant(BusSession session, String busBase, String contextPath) {
var s = impl(session);
- var down = new ArrayList<JsonMap>();
- for (var t : s.downstream)
- down.add(JsonMap.of("topic", t, "retain", policy.downstreamRetain(t).orElse(false)));
+ var down = s.downstream.stream().map(t -> JsonMap.of("topic", t, "retain", policy.downstreamRetain(t).orElse(false))).toList();
var paths = JsonMap.of("sse", busBase + "/stream/" + s.id);
var ws = webSocketPrefix;
if (ws != null)
@@ -524,7 +523,7 @@ public final class ServerBus implements AutoCloseable {
sweep(now);
var idle = policy.heartbeat();
for (var s : List.copyOf(sessions.values()))
- if (s.sink != null && ! now.isBefore(s.lastSent.plus(idle)))
+ if (s.sink.get() != null && ! now.isBefore(s.lastSent.plus(idle)))
s.offer(BusFrames.ping());
}
}
@@ -582,11 +581,9 @@ public final class ServerBus implements AutoCloseable {
/** Keeps only denied topics that are safe to echo in a 403 body: inside a topic grammar and short. */
private static List<String> echoable(List<String> denied) {
- var out = new ArrayList<String>();
- for (var x : denied)
- if (x.length() <= MAX_ECHO_LENGTH && (BusPolicy.DOWNSTREAM_PATTERN.matcher(x).matches() || BusPolicy.UPSTREAM_TOPIC.matcher(x).matches()))
- out.add(x);
- return out;
+ return denied.stream()
+ .filter(x -> x.length() <= MAX_ECHO_LENGTH && (BusPolicy.DOWNSTREAM_PATTERN.matcher(x).matches() || BusPolicy.UPSTREAM_TOPIC.matcher(x).matches()))
+ .toList();
}
private static List<String> topics(JsonMap body, String key) throws BusRefusal {
@@ -620,7 +617,7 @@ public final class ServerBus implements AutoCloseable {
return new IllegalArgumentException("E-56: " + String.format(format, args));
}
- /** A session. Every mutable field is guarded by the bus lock; {@code sink} is also volatile for {@link #isConnected()}. */
+ /** A session. Every mutable field is guarded by the bus lock; {@code sink} is also atomic for {@link #isConnected()}. */
private final class SessionImpl implements BusSession {
final String id;
@@ -633,13 +630,16 @@ public final class ServerBus implements AutoCloseable {
final Set<String> upstream;
final Instant createdAt;
- volatile FrameSink sink;
+ final AtomicReference<FrameSink> sink = new AtomicReference<>();
Instant disconnectedAt;
Instant lastSent;
long seq;
Instant windowStart = Instant.EPOCH;
int windowCount;
+ @SuppressWarnings({
+ "java:S107" // internal constructor; the parameters are the bus configuration
+ })
SessionImpl(String id, String bridgeId, String transport, String principalName, Map<String,Object> attributes,
List<String> downstream, List<String> upstream, Instant now) {
this.id = id;
@@ -660,7 +660,7 @@ public final class ServerBus implements AutoCloseable {
@Override public Object attribute(String name) { return attributes.get(name); }
@Override public Set<String> downstream() { return downstream; }
@Override public Set<String> upstream() { return upstream; }
- @Override public boolean isConnected() { return sink != null; }
+ @Override public boolean isConnected() { return sink.get() != null; }
/** Whether the grant covers a concrete topic: an exact entry, or {@code family:*} for {@code family:key}. */
boolean grants(String topic) {
@@ -672,14 +672,14 @@ public final class ServerBus implements AutoCloseable {
/** Sends a frame that carries the next {@code seq}. Not connected: nothing happens and seq is not consumed. */
boolean send(LongFunction<String> frame) {
- if (sink == null)
+ if (sink.get() == null)
return false;
return offer(frame.apply(++seq));
}
/** Offers a frame; on a full queue detaches the sink and closes it with 4429. */
boolean offer(String frame) {
- var k = sink;
+ var k = sink.get();
if (k == null)
return false;
if (k.offer(frame)) {
@@ -691,10 +691,10 @@ public final class ServerBus implements AutoCloseable {
}
void detach(int code, String reason) {
- var k = sink;
+ var k = sink.get();
if (k == null)
return;
- sink = null;
+ sink.set(null);
disconnectedAt = clock.instant();
k.close(code, reason);
}
@@ -702,7 +702,7 @@ public final class ServerBus implements AutoCloseable {
boolean expired(Instant now) {
if (! now.isBefore(createdAt.plus(policy.maxSessionAge())))
return true;
- return sink == null && ! now.isBefore(disconnectedAt.plus(policy.sessionGrace()));
+ return sink.get() == null && ! now.isBefore(disconnectedAt.plus(policy.sessionGrace()));
}
boolean admitUpstream(Instant now, int max) {
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/UpstreamHandler.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/UpstreamHandler.java
index 890c32444c..3811b01d6e 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/UpstreamHandler.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/UpstreamHandler.java
@@ -43,5 +43,8 @@ public interface UpstreamHandler {
* @param payload The JSON-object payload. Never <jk>null</jk>.
* @throws Exception Any failure; it is logged and never crosses the wire.
*/
+ @SuppressWarnings({
+ "java:S112" // SPI: any implementer failure is logged and never crosses the wire
+ })
void handle(BusSession session, String topic, JsonMap payload) throws Exception;
}
diff --git a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/package-info.java b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/package-info.java
index 528ec50f87..5c93547038 100644
--- a/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/package-info.java
+++ b/juneau-rest/juneau-rest-server-bus/src/main/java/org/apache/juneau/rest/server/bus/package-info.java
@@ -18,9 +18,9 @@
* Server half of the console message bus.
*
* <p>
- * A {@link ServerBus} holds retained topic values and the sessions that bridge them
+ * A {@link org.apache.juneau.rest.server.bus.ServerBus} holds retained topic values and the sessions that bridge them
* to pages; a {@link org.apache.juneau.rest.server.bus.BusPolicy} says what may flow, in which direction, to whom
- * (everything else is denied); {@link BusEventsMixin} exposes the CSRF-guarded session
+ * (everything else is denied); {@link org.apache.juneau.rest.server.bus.BusEventsMixin} exposes the CSRF-guarded session
* POST and the capability-gated SSE stream on a REST resource. The WebSocket transport is the separate
* {@code juneau-rest-server-bus-websocket} module.
*
diff --git a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusEventsMixin_Session_Test.java b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusEventsMixin_Session_Test.java
index 17abe4385d..1602d6d1a3 100644
--- a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusEventsMixin_Session_Test.java
+++ b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusEventsMixin_Session_Test.java
@@ -162,9 +162,12 @@ class BusEventsMixin_Session_Test extends TestBase {
}
//------------------------------------------------------------------------------------------------------------------
- // b) GET juneau-bus/stream/{sessionId}
+ // b) GET juneau-bus/stream/<sessionId>
//------------------------------------------------------------------------------------------------------------------
+ @SuppressWarnings({
+ "java:S2925" // Deadline-bounded poll for the stream to connect
+ })
@Test void b01_resyncThenLiveThenClose() throws Exception {
R.bus.publish("ops.jobs", JsonMap.of("n", 1));
var id = post(JB, body("sse", "ops.jobs", "ops.alert:*"), 200).getString("sessionId");
@@ -233,6 +236,9 @@ class BusEventsMixin_Session_Test extends TestBase {
assertFalse(body.contains("\"type\":\"resync-end\""), body);
}
+ @SuppressWarnings({
+ "java:S2925" // Deadline-bounded poll for the stream to connect
+ })
@Test void b05_aSecondStreamReplacesTheFirstQuietly() throws Exception {
var id = post(JB, body("sse", "ops.jobs"), 200).getString("sessionId");
var pool = java.util.concurrent.Executors.newFixedThreadPool(2);
diff --git a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusFrames_Test.java b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusFrames_Test.java
index 4a918b5a80..8991280302 100644
--- a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusFrames_Test.java
+++ b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusFrames_Test.java
@@ -63,7 +63,8 @@ class BusFrames_Test extends TestBase {
}
@Test void a05_encodeRejectsUnknownType() {
- var e = assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(Map.of("v", 1, "type", "nope")));
+ var frame = Map.<String,Object>of("v", 1, "type", "nope");
+ var e = assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(frame));
assertEquals("BusFrames.encode: unknown frame type 'nope'", e.getMessage());
}
@@ -78,10 +79,11 @@ class BusFrames_Test extends TestBase {
Map.of("v", 1, "type", "error", "code", "c", "message", "m", "topic", 7))) {
assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(bad), bad.toString());
}
- var e = assertThrows(IllegalArgumentException.class,
- () -> BusFrames.encode(Map.of("v", 1, "type", "pub", "topic", "ops.jobs", "payload", Map.of(), "retained", "yes")));
+ var badRetained = Map.<String,Object>of("v", 1, "type", "pub", "topic", "ops.jobs", "payload", Map.of(), "retained", "yes");
+ var e = assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(badRetained));
assertEquals("BusFrames.encode: 'retained' must be a boolean", e.getMessage());
- e = assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(Map.of("v", 1, "type", "clear")));
+ var noTopic = Map.<String,Object>of("v", 1, "type", "clear");
+ e = assertThrows(IllegalArgumentException.class, () -> BusFrames.encode(noTopic));
assertEquals("BusFrames.encode: 'topic' must be a string", e.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusPolicy_Test.java b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusPolicy_Test.java
index e6cbbd65b8..d66c29d7b0 100644
--- a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusPolicy_Test.java
+++ b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/BusPolicy_Test.java
@@ -75,11 +75,12 @@ class BusPolicy_Test extends TestBase {
//------------------------------------------------------------------------------------------------------------------
@Test void b01_badDownstreamPatterns() {
+ var b = BusPolicy.create();
for (var bad : List.of("ops", "Ops.jobs", "card:t1", "selection:t1", "cmd:*", "ops.jobs:*:*", "ops.jobs:", "a.b.c", "")) {
- var e = assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().downstream(bad, true), bad);
+ var e = assertThrows(IllegalArgumentException.class, () -> b.downstream(bad, true), bad);
assertEquals("E-57: BusPolicy: '" + bad + "' is not a valid topic pattern", e.getMessage());
}
- var e = assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().downstream(null, true));
+ var e = assertThrows(IllegalArgumentException.class, () -> b.downstream(null, true));
assertEquals("E-57: BusPolicy: 'null' is not a valid topic pattern", e.getMessage());
}
@@ -90,26 +91,30 @@ class BusPolicy_Test extends TestBase {
}
@Test void b03_upstreamWithoutHandler() {
- var e = assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().upstream("ops.cancel-all", null));
+ var b = BusPolicy.create();
+ var e = assertThrows(IllegalArgumentException.class, () -> b.upstream("ops.cancel-all", null));
assertEquals("E-57: BusPolicy: upstream topic 'ops.cancel-all' has no handler", e.getMessage());
}
@Test void b04_badUpstreamTopic() {
+ var b = BusPolicy.create();
for (var bad : List.of("ops.x:*", "job:*", "cmd:jobs", "ops")) {
- var e = assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().upstream(bad, NOOP), bad);
+ var e = assertThrows(IllegalArgumentException.class, () -> b.upstream(bad, NOOP), bad);
assertEquals("E-57: BusPolicy: '" + bad + "' is not a valid topic pattern", e.getMessage());
}
}
@Test void b05_nonPositiveLimits() {
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().sessionGrace(Duration.ZERO));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().maxSessionAge(Duration.ofSeconds(-1)));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().heartbeat(null));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().maxSessions(0));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().maxQueuedFrames(0));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().maxFrameBytes(0));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().maxUpstreamPerSecond(0));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().allowedOrigins(" "));
+ var b = BusPolicy.create();
+ assertThrows(IllegalArgumentException.class, () -> b.sessionGrace(Duration.ZERO));
+ var negative = Duration.ofSeconds(-1);
+ assertThrows(IllegalArgumentException.class, () -> b.maxSessionAge(negative));
+ assertThrows(IllegalArgumentException.class, () -> b.heartbeat(null));
+ assertThrows(IllegalArgumentException.class, () -> b.maxSessions(0));
+ assertThrows(IllegalArgumentException.class, () -> b.maxQueuedFrames(0));
+ assertThrows(IllegalArgumentException.class, () -> b.maxFrameBytes(0));
+ assertThrows(IllegalArgumentException.class, () -> b.maxUpstreamPerSecond(0));
+ assertThrows(IllegalArgumentException.class, () -> b.allowedOrigins(" "));
}
//------------------------------------------------------------------------------------------------------------------
@@ -149,21 +154,24 @@ class BusPolicy_Test extends TestBase {
@Test void d02_checkListsEveryDenial() {
var p = BusPolicy.create().downstream("ops.jobs", true).build();
- var e = assertThrows(IllegalStateException.class, () -> p.check(contract(
+ var c = contract(
JsonMap.of("id", "ops", "transport", "websocket",
- "downstream", List.of("ops.jobs", "ops.secret"), "upstream", List.of("ops.cancel-all")))));
+ "downstream", List.of("ops.jobs", "ops.secret"), "upstream", List.of("ops.cancel-all")));
+ var e = assertThrows(IllegalStateException.class, () -> p.check(c));
assertEquals("E-55: BusPolicy denies downstream topic 'ops.secret' that bridge 'ops' requests\n"
+ "E-55: BusPolicy denies upstream topic 'ops.cancel-all' that bridge 'ops' requests", e.getMessage());
}
@Test void d03_checkListsEveryDenialAcrossTopicsAndBridges() {
var p = BusPolicy.create().downstream("ops.jobs", true).build();
- var e = assertThrows(IllegalStateException.class, () -> p.check(contract(
+ var c = contract(
JsonMap.of("id", "a", "transport", "sse", "downstream", List.of("ops.x", "ops.y")),
- JsonMap.of("id", "b", "transport", "sse", "downstream", List.of("ops.z")))));
- assertEquals("E-55: BusPolicy denies downstream topic 'ops.x' that bridge 'a' requests\n"
- + "E-55: BusPolicy denies downstream topic 'ops.y' that bridge 'a' requests\n"
- + "E-55: BusPolicy denies downstream topic 'ops.z' that bridge 'b' requests", e.getMessage());
+ JsonMap.of("id", "b", "transport", "sse", "downstream", List.of("ops.z")));
+ var e = assertThrows(IllegalStateException.class, () -> p.check(c));
+ assertEquals("""
+ E-55: BusPolicy denies downstream topic 'ops.x' that bridge 'a' requests
+ E-55: BusPolicy denies downstream topic 'ops.y' that bridge 'a' requests
+ E-55: BusPolicy denies downstream topic 'ops.z' that bridge 'b' requests""", e.getMessage());
}
//------------------------------------------------------------------------------------------------------------------
@@ -178,15 +186,17 @@ class BusPolicy_Test extends TestBase {
}
@Test void e02_allowedOriginsRejectsNullAndBlank() {
- assertThrows(NullPointerException.class, () -> BusPolicy.create().allowedOrigins((String[]) null));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().allowedOrigins("https://a.example", null));
- assertThrows(IllegalArgumentException.class, () -> BusPolicy.create().allowedOrigins("https://a.example", ""));
+ var b = BusPolicy.create();
+ assertThrows(NullPointerException.class, () -> b.allowedOrigins((String[]) null));
+ assertThrows(IllegalArgumentException.class, () -> b.allowedOrigins("https://a.example", null));
+ assertThrows(IllegalArgumentException.class, () -> b.allowedOrigins("https://a.example", ""));
assertEquals(List.of("https://a.example"), BusPolicy.create().allowedOrigins("https://a.example").build().allowedOrigins());
}
@Test void e03_authorizerAndSessionAttributesRejectNull() {
- assertThrows(NullPointerException.class, () -> BusPolicy.create().authorizer(null));
- assertThrows(NullPointerException.class, () -> BusPolicy.create().sessionAttributes(null));
+ var b = BusPolicy.create();
+ assertThrows(NullPointerException.class, () -> b.authorizer(null));
+ assertThrows(NullPointerException.class, () -> b.sessionAttributes(null));
}
@Test void e04_keyedUpstreamIsExact() {
diff --git a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/ServerBus_Test.java b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/ServerBus_Test.java
index 79d2347b18..c365335e35 100644
--- a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/ServerBus_Test.java
+++ b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/ServerBus_Test.java
@@ -158,17 +158,19 @@ class ServerBus_Test extends TestBase {
@Test void a03_e56WhenThePolicyDeniesTheTopic() {
var bus = bus(policy().build());
+ var empty = JsonMap.of();
for (var t : Arrays.asList("ops.secret", "ops.alert:*", "job:1", "ops.jobs:x", null)) {
- var e = assertThrows(IllegalArgumentException.class, () -> bus.publish(t, JsonMap.of()), String.valueOf(t));
+ var e = assertThrows(IllegalArgumentException.class, () -> bus.publish(t, empty), String.valueOf(t));
assertEquals("E-56: ServerBus.publish('" + t + "'): the policy does not allow it downstream", e.getMessage());
}
- var e = assertThrows(IllegalArgumentException.class, () -> bus.publishTo(s -> true, "ops.secret", JsonMap.of()));
+ var e = assertThrows(IllegalArgumentException.class, () -> bus.publishTo(s -> true, "ops.secret", empty));
assertEquals("E-56: ServerBus.publishTo('ops.secret'): the policy does not allow it downstream", e.getMessage());
}
@Test void a04_e56WhenTheFrameIsTooLarge() {
var bus = bus(policy().maxFrameBytes(256).build());
- var e = assertThrows(IllegalArgumentException.class, () -> bus.publish("ops.jobs", JsonMap.of("blob", "x".repeat(300))));
+ var big = JsonMap.of("blob", "x".repeat(300));
+ var e = assertThrows(IllegalArgumentException.class, () -> bus.publish("ops.jobs", big));
assertTrue(e.getMessage().startsWith("E-56: ServerBus.publish('ops.jobs'): frame too large ("), e.getMessage());
assertTrue(bus.retainedJson("ops.jobs").isEmpty(), "a refused publish stores nothing");
assertTrue(bus.publish("ops.jobs", JsonMap.of("blob", "x".repeat(10))));
@@ -295,12 +297,13 @@ class ServerBus_Test extends TestBase {
}
@Test void b08_enableWebSocketValidatesThePrefix() {
- var bus = new ServerBus(policy().build(), clock, null);
- for (var bad : Arrays.asList("juneau-bus/ws", "/juneau-bus/ws/", null))
- assertThrows(IllegalArgumentException.class, () -> bus.enableWebSocket(bad), String.valueOf(bad));
- assertNull(bus.webSocketPrefix());
- bus.enableWebSocket("/juneau-bus/ws");
- assertEquals("/juneau-bus/ws", bus.webSocketPrefix());
+ try (var bus = new ServerBus(policy().build(), clock, null)) {
+ for (var bad : Arrays.asList("juneau-bus/ws", "/juneau-bus/ws/", null))
+ assertThrows(IllegalArgumentException.class, () -> bus.enableWebSocket(bad), String.valueOf(bad));
+ assertNull(bus.webSocketPrefix());
+ bus.enableWebSocket("/juneau-bus/ws");
+ assertEquals("/juneau-bus/ws", bus.webSocketPrefix());
+ }
}
@Test void b09_grantDescribesTheSession() throws Exception {
@@ -674,7 +677,8 @@ class ServerBus_Test extends TestBase {
var worst = BusFrames.utf8Length(BusFrames.pub("ops.jobs", Json.of("x".repeat(10)), false, Long.MAX_VALUE));
var bus = bus(policy().maxFrameBytes(worst).build());
assertTrue(bus.publish("ops.jobs", "x".repeat(10)), "exactly maxFrameBytes is accepted");
- var e = assertThrows(IllegalArgumentException.class, () -> bus.publish("ops.jobs", "x".repeat(11)));
+ var tooBig = "x".repeat(11);
+ var e = assertThrows(IllegalArgumentException.class, () -> bus.publish("ops.jobs", tooBig));
assertTrue(e.getMessage().contains("frame too large"), e.getMessage());
var frame = up("ops.cancel-all", "{\"reason\":\"" + "y".repeat(20) + "\"}");
@@ -713,6 +717,9 @@ class ServerBus_Test extends TestBase {
@Override public void close(int code, String reason) { /* nothing to do */ }
}
+ @SuppressWarnings({
+ "java:S2925" // Stress-run window; the workers run for a fixed time
+ })
@Test void h07_concurrentPublishConnectDisconnectKeepsSeqAndResyncOrder() throws Exception {
var bus = bus(policy().maxQueuedFrames(1_000_000).build());
var stop = new AtomicBoolean();
diff --git a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/SseFrameSink_Test.java b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/SseFrameSink_Test.java
index ed0034c79e..89a7d48ced 100644
--- a/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/SseFrameSink_Test.java
+++ b/juneau-rest/juneau-rest-server-bus/src/test/java/org/apache/juneau/rest/server/bus/SseFrameSink_Test.java
@@ -48,6 +48,9 @@ class SseFrameSink_Test extends TestBase {
return e.getData();
}
+ @SuppressWarnings({
+ "java:S2925" // Timing helper; the tests under test are time-driven
+ })
private static void sleep(long ms) {
try {
Thread.sleep(ms);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker-datatables/.sonarlint/connectedMode.json b/juneau-rest/juneau-rest-server-console-ui-freemarker-datatables/.sonarlint/connectedMode.json
new file mode 100644
index 0000000000..76a32b7486
--- /dev/null
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker-datatables/.sonarlint/connectedMode.json
@@ -0,0 +1,5 @@
+{
+ "sonarCloudOrganization": "apache",
+ "projectKey": "apache_juneau",
+ "region": "EU"
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrlMethodModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrlMethodModel.java
index b847c6e096..32805db7e7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrlMethodModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrlMethodModel.java
@@ -94,7 +94,7 @@ public final class AssetUrlMethodModel implements TemplateMethodModelEx {
return "";
}
if (devMode)
- LOG.warning("assetUrl: no bundled resource '" + resource + "' for '" + path + "'; serving it unversioned.");
+ LOG.log(Level.WARNING, () -> "assetUrl: no bundled resource '" + resource + "' for '" + path + "'; serving it unversioned.");
return "";
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BadgeDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BadgeDirectiveModel.java
index 21a1b52b8b..90b02f8cde 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BadgeDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BadgeDirectiveModel.java
@@ -50,6 +50,10 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class BadgeDirectiveModel implements TemplateDirectiveModel {
/** The shared-variable name this directive registers under. */
@@ -173,9 +177,7 @@ public final class BadgeDirectiveModel implements TemplateDirectiveModel {
for (var e : values)
if (wire.apply(e).equals(v))
return e;
- var allowed = new ArrayList<String>();
- for (var e : values)
- allowed.add(wire.apply(e));
+ var allowed = Arrays.stream(values).map(wire).toList();
throw FtlAttrLists.reject(f("<@badge id='%s'> %s= '%s' is not one of '%s'.", badgeId, attr, v,
String.join(", ", allowed)));
}
@@ -187,9 +189,7 @@ public final class BadgeDirectiveModel implements TemplateDirectiveModel {
for (var e : m.entrySet()) {
if (! (e.getValue() instanceof List<?> l))
throw FtlAttrLists.reject("<@badge id='" + badgeId + "'> scopeValues must be a JSON5 object of string lists.");
- var vals = new ArrayList<String>();
- for (var item : l)
- vals.add(String.valueOf(item));
+ var vals = new ArrayList<>(l.stream().map(Objects::toString).toList());
out.put(String.valueOf(e.getKey()), vals);
}
return out;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirectiveModel.java
index 3b6295d6e0..405e698183 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirectiveModel.java
@@ -41,6 +41,9 @@ import freemarker.template.utility.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class BridgeDirectiveModel implements TemplateDirectiveModel {
/** The shared-variable name this directive registers under. */
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs.java
index e5f0aac38b..6e2e796fb2 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs.java
@@ -24,6 +24,10 @@ import org.apache.juneau.rest.server.console.*;
import org.apache.juneau.rest.server.console.Subscription.*;
/** Lowers {@code <@card subscribes/publishes>} (attribute or JSON5 body) through the {@link Subscription} and {@link TopicDecl} builders. */
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
final class CardBusAttrs {
private static final Set<String> SUB_KEYS = new LinkedHashSet<>(List.of("topic", "as", "map", "whenEmpty", "emptyText"));
@@ -96,11 +100,7 @@ final class CardBusAttrs {
if (v == null)
return List.of();
if (v instanceof String s) {
- var l = new ArrayList<String>();
- for (var part : s.split(","))
- if (! part.isBlank())
- l.add(part.trim());
- return l;
+ return Arrays.stream(s.split(",")).filter(part -> ! part.isBlank()).map(String::trim).toList();
}
if (v instanceof Collection<?> c)
return List.copyOf(c);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirectiveModel.java
index c5d7c114d9..8bfb823165 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirectiveModel.java
@@ -24,7 +24,6 @@ import java.util.regex.*;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.marshall.json5.*;
-import org.apache.juneau.marshall.parser.*;
import org.apache.juneau.rest.server.console.*;
import org.apache.juneau.rest.server.views.*;
@@ -64,7 +63,8 @@ import freemarker.template.utility.*;
* @since 10.0.0
*/
@SuppressWarnings({
- "java:S1192" // Duplicated literals read more clearly inline than as constants
+ "java:S1192", // Duplicated literals read more clearly inline than as constants
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
})
public final class CardDirectiveModel implements TemplateDirectiveModel {
@@ -233,6 +233,9 @@ public final class CardDirectiveModel implements TemplateDirectiveModel {
}
}
+ @SuppressWarnings({
+ "java:S107" // Internal helper whose parameters are the render/validation context.
+ })
private static void htmlCard(PageCapture cap, String id, String title, String src, String template, String markup,
String cssClass, boolean sanitize, Object pubs, Object subs)
throws TemplateModelException {
@@ -272,6 +275,9 @@ public final class CardDirectiveModel implements TemplateDirectiveModel {
* {@link CardTypeRegistry} (a registered handler such as {@code datatables}, {@code terminal} or {@code job-log}, or the
* generic passthrough for an unregistered type).
*/
+ @SuppressWarnings({
+ "java:S107" // Internal helper whose parameters are the render/validation context.
+ })
private CardSpec registryCard(PageCapture cap, String type, String id, String title, String src, String template,
String markup, String cssClass, Object pubs, Object subs) throws TemplateModelException {
if (id.isEmpty())
@@ -376,6 +382,7 @@ public final class CardDirectiveModel implements TemplateDirectiveModel {
* render. The shell mounts it through {@code JuneauViews.runView.mount}.
*/
@SuppressWarnings({
+ "java:S107", // Internal helper whose parameters are the render/validation context.
"unchecked" // JSON5 object keys are always strings.
})
private static void runViewCard(PageCapture cap, String id, String title, String src, String template,
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec.java
index b4f9407b8f..ae34dc984c 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec.java
@@ -51,7 +51,8 @@ public final class CardSpec {
private boolean sanitize;
private String cssClass;
private final Map<String,Object> body = new LinkedHashMap<>();
- private final List<Map<String,Object>> publishes = new ArrayList<>(), subscribes = new ArrayList<>();
+ private final List<Map<String,Object>> publishes = new ArrayList<>();
+ private final List<Map<String,Object>> subscribes = new ArrayList<>();
private List<VisibilityRule> visibleWhen = List.of();
private CardSpec(String type, String id) {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartCardType.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartCardType.java
index 3c47c0b257..85ef255bb1 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartCardType.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartCardType.java
@@ -63,6 +63,10 @@ import org.apache.juneau.rest.server.console.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class ChartCardType implements CardTypeHandler {
// The non-safe methods only: a safe method skips the server's Origin and CSRF checks.
@@ -71,7 +75,9 @@ public final class ChartCardType implements CardTypeHandler {
private static final Set<String> OPS = Set.of("highlight", "downplay", "showTip", "hideTip", "zoomTo", "legendSelect", "export", "refresh");
/** Public no-arg constructor, required by {@link java.util.ServiceLoader}. */
- public ChartCardType() {}
+ public ChartCardType() {
+ // No state; instantiated by ServiceLoader.
+ }
@Override
public String type() {
@@ -127,7 +133,11 @@ public final class ChartCardType implements CardTypeHandler {
throw source.error("type='chart' requires 'helper', a legacy 'kind' or an 'option'.");
if (body.containsKey("helper") && ! (body.get("helper") instanceof Map))
throw source.error("type='chart' helper must be a JSON object.");
- Map<?,?> helper = body.get("helper") instanceof Map<?,?> h ? h : body.containsKey("kind") ? body : null;
+ Map<?,?> helper = null;
+ if (body.get("helper") instanceof Map<?,?> h)
+ helper = h;
+ else if (body.containsKey("kind"))
+ helper = body;
if (helper != null)
checkHelper(source, helper);
for (var k : List.of("option", "patch"))
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef.java
index 4b461cdf9e..fa116628c5 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef.java
@@ -21,6 +21,7 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
import org.apache.juneau.commons.http.*;
+import org.apache.juneau.commons.utils.Shorts;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.marshall.json5.*;
import org.apache.juneau.marshall.marshaller.Json;
@@ -46,6 +47,10 @@ import org.apache.juneau.rest.server.views.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class ChartDef {
/** Minimum chart height in pixels. */
@@ -83,8 +88,11 @@ public final class ChartDef {
// on the CardSpec that toCardSpec() returns, never through set(...).
private static final Set<String> CARD_LEVEL = Set.of("publishes", "subscribes", "template", "bare", "class");
- private final String kind, id;
- private String title, src, source;
+ private final String kind;
+ private final String id;
+ private String title;
+ private String src;
+ private String source;
private List<Map<String,Object>> data;
private final Map<String,Object> body = new LinkedHashMap<>();
private final List<Map<String,Object>> series = new ArrayList<>();
@@ -406,7 +414,7 @@ public final class ChartDef {
/** @param fields The treemap group fields, outermost first; at least one, each non-blank. @return This object. */
public ChartDef groupBy(String... fields) {
only("treemap", "groupBy");
- if (fields == null || fields.length == 0 || Arrays.stream(fields).anyMatch(f -> ib(f)))
+ if (fields == null || fields.length == 0 || Arrays.stream(fields).anyMatch(Shorts::ib))
throw iaex("ChartDef '%s' groupBy requires at least one non-blank field.", id);
body.put("groupBy", List.of(fields));
return this;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChoiceSection.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChoiceSection.java
index cd46aa45e4..abaae18f5d 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChoiceSection.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ChoiceSection.java
@@ -44,6 +44,9 @@ import org.apache.juneau.rest.server.console.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class ChoiceSection extends Section {
private final String source;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirectiveModel.java
index e6bd28e95d..bbc6312bbe 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirectiveModel.java
@@ -107,7 +107,8 @@ public final class ConsoleDirectiveModel implements TemplateDirectiveModel {
if (! schemeAttr.isEmpty() && ! ConsoleChromeMixin.SCHEMES.contains(schemeAttr))
throw FtlAttrLists.reject("<@console> unknown scheme '" + schemeAttr + "'. Schemes: "
+ String.join(", ", ConsoleChromeMixin.SCHEMES) + ".");
- var scheme = ! schemeAttr.isEmpty() ? schemeAttr : nn(cap.scheme()) ? cap.scheme() : ConsoleChromeMixin.SCHEMES.get(0);
+ var capScheme = nn(cap.scheme()) ? cap.scheme() : ConsoleChromeMixin.SCHEMES.get(0);
+ var scheme = ! schemeAttr.isEmpty() ? schemeAttr : capScheme;
var schemeToggle = FtlAttrLists.strictBoolean(p, NAME, "schemeToggle", cap.schemeToggle());
var icon = FtlAttrLists.scalar(p, "icon");
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin.java
index a8c1308d6c..38f6dedfd7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin.java
@@ -19,7 +19,7 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.console.*;
@@ -83,6 +83,9 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public class ConsoleFreemarkerMixin extends FreemarkerMixin {
static {
@@ -294,7 +297,7 @@ public class ConsoleFreemarkerMixin extends FreemarkerMixin {
final List<ToolkitPack> extraPacks = new ArrayList<>();
final List<String> providedPacks = new ArrayList<>();
final List<String> requiredPacks = new ArrayList<>();
- Function<String,String> webJarProbe = WebJarResolver::resolvePath;
+ UnaryOperator<String> webJarProbe = WebJarResolver::resolvePath;
final CardRequirements.Builder cardRequirements = CardRequirements.create();
final CardTypeRegistry.Builder cardTypes = CardTypeRegistry.standard().copy();
boolean devMode = Boolean.getBoolean("juneau.console.devMode");
@@ -390,7 +393,7 @@ public class ConsoleFreemarkerMixin extends FreemarkerMixin {
}
// Package-private: tests simulate an absent WebJar (the jar is on every test classpath).
- Builder webJarProbe(Function<String,String> probe) {
+ Builder webJarProbe(UnaryOperator<String> probe) {
webJarProbe = rnn(probe);
return this;
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator.java
index e29dc274ad..1a517290ec 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator.java
@@ -22,7 +22,7 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
import java.util.regex.*;
import java.util.stream.*;
@@ -59,7 +59,8 @@ import freemarker.template.*;
* @since 10.0.0
*/
@SuppressWarnings({
- "java:S1075" // "/" is the template-name separator, not a file-system path.
+ "java:S1075", // "/" is the template-name separator, not a file-system path.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
})
public final class ConsoleTemplateValidator {
@@ -130,7 +131,7 @@ public final class ConsoleTemplateValidator {
private String classpathRoot;
private String chromeTemplate;
private final Set<String> allowed = new TreeSet<>();
- private Function<String,String> webJarProbe = WebJarResolver::resolvePath;
+ private UnaryOperator<String> webJarProbe = WebJarResolver::resolvePath;
private final ToolkitPackRegistry packs = new ToolkitPackRegistry();
private String echartsProblem; // cached E-70 (or invalid-pack-graph) message; null when the probe passed
private String echartsRule; // the rule id the cached problem is reported under
@@ -202,7 +203,7 @@ public final class ConsoleTemplateValidator {
}
// Package-private: tests simulate an absent WebJar.
- ConsoleTemplateValidator webJarProbe(Function<String,String> probe) {
+ ConsoleTemplateValidator webJarProbe(UnaryOperator<String> probe) {
webJarProbe = rnn(probe);
echartsProbed = false;
return this;
@@ -383,7 +384,7 @@ public final class ConsoleTemplateValidator {
var a = ASSET_REF.matcher(text);
while (a.find()) {
- var url = nn(a.group(1)) ? a.group(1) : a.group(2);
+ var url = a.group(nn(a.group(1)) ? 1 : 2);
if (! url.contains("${") && ! url.contains("<#") && JUNEAU_ASSET.matcher(url).find())
add(out, name, lines, a.start(), "hardcoded-asset-url", f(
"Hard-coded Juneau asset URL '%s' is unversioned and goes stale in browser caches; use viewAssetUrl(...), consoleJsUrl(...), chromeCssUrl(...) or themeAssetUrl(...) so it carries ?v= (an adopter's own assets can use assetUrl(...)).", url));
@@ -433,6 +434,9 @@ public final class ConsoleTemplateValidator {
* The C2 card-body rules: {@code card-src-and-body} and {@code card-reserved-key}.
* Reads the body the same way {@link #checkViewVersion} does, up to the next {@code </@card}.
*/
+ @SuppressWarnings({
+ "java:S107" // Internal helper whose parameters are the render/validation context.
+ })
private static void checkCardBody(List<Finding> out, String name, int[] lines, int at, String text, int bodyStart, Value id, Value src, Value type) {
var end = text.indexOf("</@card", bodyStart);
var body = text.substring(bodyStart, end < 0 ? text.length() : end);
@@ -499,7 +503,7 @@ public final class ConsoleTemplateValidator {
String v;
boolean literal;
if (nn(m.group(2)) || nn(m.group(3))) {
- v = nn(m.group(2)) ? m.group(2) : m.group(3);
+ v = m.group(nn(m.group(2)) ? 2 : 3);
literal = ! v.contains("${");
} else {
v = m.group(4);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec.java
index 1276b71d2f..7387fc430a 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec.java
@@ -42,6 +42,9 @@ import org.apache.juneau.rest.server.console.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class DashboardSpec {
/** A panel: a card this dashboard adds, or the id of a card already on the page. */
@@ -211,10 +214,7 @@ public final class DashboardSpec {
/** @return The cards this dashboard adds to the page: the built panels, then the card sections, in order. */
List<CardSpec> ownedCards() {
- var out = new ArrayList<CardSpec>();
- for (var p : panels)
- if (p.card() != null)
- out.add(p.card());
+ var out = new ArrayList<CardSpec>(panels.stream().map(Panel::card).filter(Objects::nonNull).toList());
if (rail != null)
for (var s : rail.sections())
out.addAll(s.cards());
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef.java
index c21958d0f3..c625352af7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef.java
@@ -44,6 +44,9 @@ import org.apache.juneau.rest.server.console.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class DataSourceDef {
static final String E76 = "E-76: data source '%s': %s";
@@ -51,7 +54,7 @@ public final class DataSourceDef {
static final Set<String> BUCKETS = Set.of("hour", "day", "week", "month", "auto");
static final Pattern FIELD = Pattern.compile("^[^,()\\s]+$");
static final Pattern MEASURE = Pattern.compile("^(count|(sum|avg|min|max)\\([^,()\\s]+\\))$");
- static final Pattern DOTTED_PATH = Pattern.compile("^[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*$");
+ static final Pattern DOTTED_PATH = Pattern.compile("^[A-Za-z0-9_-]++(?:\\.[A-Za-z0-9_-]++)*+$");
/** The built-in parser for each wire format. */
public enum Format {
@@ -75,7 +78,9 @@ public final class DataSourceDef {
/** How the window is split into requests; UTC calendar units. */
public static final class Chunking {
- final String unit, start, end;
+ final String unit;
+ final String start;
+ final String end;
private Chunking(String unit, String start, String end) {
this.unit = unit;
@@ -155,11 +160,17 @@ public final class DataSourceDef {
}
private final String id;
- private String url, parser = "csv", builder = "columnar", aggregateUrl, epochUrl, epochPath;
+ private String url;
+ private String parser = "csv";
+ private String builder = "columnar";
+ private String aggregateUrl;
+ private String epochUrl;
+ private String epochPath;
private final List<JsonMap> columns = new ArrayList<>();
private final List<JsonMap> subscribes = new ArrayList<>();
private Chunking chunk = Chunking.none();
- private int concurrency = 1, debounceMs = 250;
+ private int concurrency = 1;
+ private int debounceMs = 250;
private Cache cache = Cache.memory();
private Mode mode = Mode.RAW;
private Long maxRows;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType.java
index b3dca18e92..4b63234b2c 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType.java
@@ -20,6 +20,8 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
import java.util.logging.*;
+import java.util.regex.*;
+import java.util.stream.*;
import org.apache.juneau.commons.beanquery.*;
import org.apache.juneau.marshall.collections.*;
@@ -43,10 +45,17 @@ import org.apache.juneau.rest.server.widgets.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class DatatablesCardType implements CardTypeHandler {
private static final Logger LOG = Logger.getLogger(DatatablesCardType.class.getName());
+ /** A <c>{token}</c> placeholder in an endpoint template. */
+ private static final Pattern PLACEHOLDER = Pattern.compile("\\{[^}]+\\}");
+
/** Inline {@code rows} count above which a {@code WARNING} steers the author to {@code dataUrl}. */
private static final int ROWS_WARN_THRESHOLD = 1_000;
@@ -60,7 +69,9 @@ public final class DatatablesCardType implements CardTypeHandler {
"searchType", "searchOperators", "customOperators");
/** Public no-arg constructor, required by {@link java.util.ServiceLoader}. */
- public DatatablesCardType() {}
+ public DatatablesCardType() {
+ // No state; instantiated by ServiceLoader.
+ }
/** The {@code cmd:<id>} ops the datatables JS handles, beyond the shell's {@code refresh}. */
static final Set<String> TABLE_OPS = Set.of(
@@ -267,7 +278,8 @@ public final class DatatablesCardType implements CardTypeHandler {
private static String columnIdent(Map<String,Object> col) {
var data = col.get("data");
var key = col.get("key");
- return nn(data) ? data.toString() : (nn(key) ? key.toString() : null);
+ var fallback = nn(key) ? key.toString() : null;
+ return nn(data) ? data.toString() : fallback;
}
private static final Set<String> QUICK_STAT_KINDS = Set.of("tile", "meter", "segmented");
@@ -298,7 +310,8 @@ public final class DatatablesCardType implements CardTypeHandler {
if (type == null) {
if (hasSegments && hasMax)
throw source.error("quickStats item '%s': has both segments and max; set type.", id);
- kind = hasSegments ? "segmented" : hasMax ? "meter" : "tile";
+ var unsegmented = hasMax ? "meter" : "tile";
+ kind = hasSegments ? "segmented" : unsegmented;
} else {
if (! (type instanceof String t) || ! QUICK_STAT_KINDS.contains(t))
throw source.error("quickStats item '%s': unknown type '%s'.", id, type);
@@ -409,10 +422,7 @@ public final class DatatablesCardType implements CardTypeHandler {
}
private static String knownSearchTypes() {
- var names = new ArrayList<String>();
- for (var t : SearchType.values())
- names.add(t.wire());
- return String.join(", ", names);
+ return Arrays.stream(SearchType.values()).map(SearchType::wire).collect(Collectors.joining(", "));
}
private static String knownOperators(Set<String> customNames) {
@@ -435,11 +445,11 @@ public final class DatatablesCardType implements CardTypeHandler {
return;
for (var raw : actions) {
var action = (Map<String,Object>) raw;
- var mode = nn(action.get("mode")) ? action.get("mode") : action.get("bulkMode");
+ var mode = action.get(nn(action.get("mode")) ? "mode" : "bulkMode");
if (! eq("aggregate", mode))
continue;
var endpoint = str(action.get("endpoint"));
- if (nn(endpoint) && endpoint.matches(".*\\{[^}]+\\}.*"))
+ if (nn(endpoint) && PLACEHOLDER.matcher(endpoint).find())
throw iaex(
"Bulk action '%s' has mode 'aggregate' but its endpoint '%s' contains a {field} token; "
+ "aggregate endpoints receive {ids} in the body.", action.get("id"), endpoint);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCardType.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCardType.java
index 660844a268..b36f58681d 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCardType.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCardType.java
@@ -58,6 +58,9 @@ import org.apache.juneau.rest.server.views.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class JobLogCardType implements CardTypeHandler {
/** The smallest accepted {@code height}, in pixels. */
@@ -67,7 +70,9 @@ public final class JobLogCardType implements CardTypeHandler {
private static final Pattern URL_PARAM = Pattern.compile("[A-Za-z][A-Za-z0-9_-]*");
/** Public no-arg constructor, required by {@link java.util.ServiceLoader}. */
- public JobLogCardType() {}
+ public JobLogCardType() {
+ // No state; instantiated by ServiceLoader.
+ }
@Override
public String type() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Markers.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Markers.java
index cd3b4c50a1..29227c3b64 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Markers.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Markers.java
@@ -19,6 +19,7 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
+import java.util.stream.*;
import org.apache.juneau.commons.http.*;
import org.apache.juneau.marshall.collections.*;
@@ -96,10 +97,7 @@ public final class Markers implements Decorator {
static List<Map<String,Object>> copyRows(List<? extends Map<String,?>> rows) {
if (rows == null)
throw iaex("Decorator values must not be null.");
- var out = new ArrayList<Map<String,Object>>();
- for (var r : rows)
- out.add(new LinkedHashMap<>(r));
- return out;
+ return rows.stream().<Map<String,Object>>map(LinkedHashMap::new).collect(Collectors.toCollection(ArrayList::new));
}
static String dataTopicOf(String who, String topic) {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/NodeDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/NodeDirectiveModel.java
index eb69a83981..dc777cae6c 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/NodeDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/NodeDirectiveModel.java
@@ -69,6 +69,10 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class NodeDirectiveModel implements TemplateDirectiveModel {
/** The shared-variable name this directive registers under. */
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture.java
index d38f442d21..0c37c4a744 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture.java
@@ -22,6 +22,7 @@ import java.io.*;
import java.util.*;
import java.util.function.*;
import java.util.regex.*;
+import java.util.stream.*;
import org.apache.juneau.commons.http.*;
import org.apache.juneau.marshall.collections.*;
@@ -56,7 +57,8 @@ import freemarker.template.utility.*;
* @since 10.0.0
*/
@SuppressWarnings({
- "java:S1192" // Duplicated literals read more clearly inline than as constants
+ "java:S1192", // Duplicated literals read more clearly inline than as constants
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
})
public final class PageCapture {
@@ -152,7 +154,9 @@ public final class PageCapture {
private Map<String,Object> dashboard;
private final Map<String,Map<String,Object>> dataSources = new LinkedHashMap<>();
private final Map<String,BadgeDef> badges = new LinkedHashMap<>();
- private Map<String,Object> javaFacts = Map.of(), chromeFacts = Map.of(), facts = Map.of();
+ private Map<String,Object> javaFacts = Map.of();
+ private Map<String,Object> chromeFacts = Map.of();
+ private Map<String,Object> facts = Map.of();
// Cards from a PageSpec, held until placed or the page closes. builtCards: not yet placed, in declaration order.
// builtCardIds: every id ever registered here, kept after placement.
private final Map<String,CardSpec> builtCards = new LinkedHashMap<>();
@@ -791,11 +795,8 @@ public final class PageCapture {
}
private static Set<String> bodyAttrNames(String text) {
- var names = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
- for (var a : tokenizeBodyAttrs(text))
- if (a.hasValue())
- names.add(a.name());
- return names;
+ return tokenizeBodyAttrs(text).stream().filter(BodyAttr::hasValue).map(BodyAttr::name)
+ .collect(Collectors.toCollection(() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));
}
/**
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec.java
index d34dec9f6d..59fc665a15 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec.java
@@ -21,6 +21,7 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import java.util.*;
import java.util.function.*;
import java.util.regex.*;
+import java.util.stream.*;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.rest.server.*;
@@ -67,6 +68,10 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1845", // Fluent-builder setters intentionally mirror field names (Juneau DSL convention)
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class PageSpec {
/** Data-model attribute that carries the spec into the render. */
@@ -706,9 +711,7 @@ public final class PageSpec {
* nav-node check needs the resolved chrome, so it only runs at {@code </...@console>}.
*/
private void checkBadgesAgainstOwnCards() {
- var cardIds = new HashSet<String>();
- for (var c : cards)
- cardIds.add(c.id());
+ var cardIds = cards.stream().map(CardSpec::id).collect(Collectors.toSet());
for (var b : badges) {
var m = b.toContractMap();
for (var card : PageCapture.badgeCardRefs(m))
@@ -888,6 +891,9 @@ public final class PageSpec {
// The exact-type-else-registered-subtype lookup the renderer runs, without its two-beans ambiguity check (the
// renderer still reports that itself at render time).
+ @SuppressWarnings({
+ "resource" // The request context owns its bean store.
+ })
private static ConsoleFreemarkerMixin resolveConsoleMixin(RestRequest req) {
var store = req.getContext().getBeanStore();
FreemarkerMixin found = store.getBean(FreemarkerMixin.class).orElse(null);
@@ -946,10 +952,15 @@ public final class PageSpec {
throw FtlAttrLists.reject("PageSpec cards need the console card directive; the render has no ConsoleFreemarkerMixin.");
for (var card : cards) {
var markup = cardMarkup.get(card.id());
- var built = tableBodies.containsKey(card.id()) ? new Built(liftTable(card, cardModel), markup)
- : LIFTED_TYPES.contains(card.type()) ? new Built(liftChecked(card, cardModel), markup)
- : CardTypeRegistry.RESERVED.contains(card.type()) ? new Built(card.copy(), markup)
- : liftCustom(card, markup, cardModel);
+ Built built;
+ if (tableBodies.containsKey(card.id()))
+ built = new Built(liftTable(card, cardModel), markup);
+ else if (LIFTED_TYPES.contains(card.type()))
+ built = new Built(liftChecked(card, cardModel), markup);
+ else if (CardTypeRegistry.RESERVED.contains(card.type()))
+ built = new Built(card.copy(), markup);
+ else
+ built = liftCustom(card, markup, cardModel);
cap.addBuiltCard(built.card(), built.markupOrNull());
cardModel.recordRequirements(cap, built.card().type(), built.card().id(), List.of(), built.card().bodyMap());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec.java
index 53e744bbf1..a5515b9964 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec.java
@@ -38,6 +38,9 @@ import java.util.regex.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1845" // Fluent-builder setters intentionally mirror field names (Juneau DSL convention)
+})
public final class PersistSpec {
private static final Pattern NS = Pattern.compile("^[a-z][a-z0-9.-]{0,63}$");
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Rail.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Rail.java
index 1bc2b01364..b0397aece1 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Rail.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Rail.java
@@ -95,9 +95,7 @@ public final class Rail {
/** @return The rail JSON. */
Map<String,Object> toMap() {
- var list = new ArrayList<Map<String,Object>>();
- for (var s : sections)
- list.add(s.toMap());
+ var list = sections.stream().map(Section::toMap).toList();
var m = new LinkedHashMap<String,Object>();
m.put("side", side);
m.put("width", width);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/RangeSection.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/RangeSection.java
index b103b5dd79..94bbaadec4 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/RangeSection.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/RangeSection.java
@@ -36,9 +36,12 @@ import java.util.regex.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class RangeSection extends Section {
- private static final Pattern PRESET = Pattern.compile("^([1-9][0-9]{0,3}[dh]|ytd)$");
+ private static final Pattern PRESET = Pattern.compile("^([1-9]\\d{0,3}[dh]|ytd)$");
private final List<String> presets;
private boolean custom;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Section.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Section.java
index f37b63ca29..debc5a1a90 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Section.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/Section.java
@@ -163,6 +163,9 @@ public abstract class Section {
}
/** @return <jk>true</jk> if {@code name} is a dotted extension name (the E-74 shape). */
+ @SuppressWarnings({
+ "java:S2692" // A leading dot is deliberately invalid, so indexOf must be > 0, not >= 0.
+ })
static boolean isDottedName(String name) {
return name != null && name.indexOf('.') > 0 && BusWiringValidator.EXTENSION_NAME.matcher(name).matches();
}
@@ -184,7 +187,7 @@ public abstract class Section {
Custom(String name, JsonMap args) {
this.name = name;
- this.args = args == null ? JsonMap.of() : new JsonMap((Map<?,?>)args);
+ this.args = args == null ? JsonMap.of() : new JsonMap(args);
}
@Override /* Section */
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType.java
index 90a538d6b5..5d3b251fce 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType.java
@@ -36,12 +36,17 @@ import org.apache.juneau.rest.server.terminal.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class TerminalCardType implements CardTypeHandler {
private static final Set<String> BODY_KEYS = new LinkedHashSet<>(List.of("contractVersion", "terminal"));
/** Public no-arg constructor, required by {@link java.util.ServiceLoader}. */
- public TerminalCardType() {}
+ public TerminalCardType() {
+ // No state; instantiated by ServiceLoader.
+ }
@Override
public String type() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ThemeDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ThemeDirectiveModel.java
index 832440dcae..2251a19879 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ThemeDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ThemeDirectiveModel.java
@@ -80,6 +80,9 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class ThemeDirectiveModel implements TemplateDirectiveModel {
/** The shared-variable name this directive registers under. */
@@ -128,8 +131,8 @@ public final class ThemeDirectiveModel implements TemplateDirectiveModel {
// stray <@token> outside a <@theme> (e.g. in a sibling directive's body) fails its own "must be nested" guard.
// A nameless directive seeds from the page theme: console theme=, else the PageSpec theme, else the default.
if (! named) {
- name = nn(cap.consoleTheme) ? cap.consoleTheme : nn(cap.themeOrNull()) ? cap.themeOrNull()
- : ConsoleChromeMixin.BUILTIN_THEME_NAMES.get(0);
+ var pageTheme = nn(cap.themeOrNull()) ? cap.themeOrNull() : ConsoleChromeMixin.BUILTIN_THEME_NAMES.get(0);
+ name = nn(cap.consoleTheme) ? cap.consoleTheme : pageTheme;
}
var seed = ConsoleChromeMixin.stockTheme(name);
var themeBuilder = Theme.create(name);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TokenDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TokenDirectiveModel.java
index e05d0e4e82..c8a0ab34c9 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TokenDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TokenDirectiveModel.java
@@ -75,7 +75,8 @@ import freemarker.template.*;
* @since 10.0.0
*/
@SuppressWarnings({
- "java:S1192" // Duplicated literals read more clearly inline than as constants
+ "java:S1192", // Duplicated literals read more clearly inline than as constants
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
})
public final class TokenDirectiveModel implements TemplateDirectiveModel {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry.java
index 2055661a67..85b85b05d7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry.java
@@ -20,7 +20,7 @@ import static org.apache.juneau.commons.utils.Shorts.*;
import static org.apache.juneau.rest.server.view.freemarker.console.ToolkitPack.Kind.*;
import java.util.*;
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
import java.util.logging.*;
import org.apache.juneau.rest.server.*;
@@ -77,6 +77,9 @@ import org.apache.juneau.rest.server.widgets.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class ToolkitPackRegistry {
private static final Logger LOG = Logger.getLogger(ToolkitPackRegistry.class.getName());
@@ -344,7 +347,7 @@ public final class ToolkitPackRegistry {
}
// Package-private: the probe is injectable because the echarts jar is on every test classpath.
- synchronized ToolkitPackRegistry checkWebJars(Collection<String> roots, Function<String,String> probe) {
+ synchronized ToolkitPackRegistry checkWebJars(Collection<String> roots, UnaryOperator<String> probe) {
for (var pack : expand(new LinkedHashSet<>(roots), "requirePacks")) {
if (provided.contains(pack.name()) || pack.kind() != VENDOR || pack.resolver() != WEBJAR_RESOLVER)
continue;
@@ -451,7 +454,7 @@ public final class ToolkitPackRegistry {
}
var dup = pageFiles.get(fileName(url));
if (nn(dup)) {
- LOG.warning(f("Template '%s': skipped pack '%s' asset %s; the page already loads %s.", template, pack.name(), url, dup));
+ LOG.log(Level.WARNING, () -> f("Template '%s': skipped pack '%s' asset %s; the page already loads %s.", template, pack.name(), url, dup));
continue;
}
out.add(url);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirectiveModel.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirectiveModel.java
index 9d58fe4622..78939e7ff2 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirectiveModel.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/main/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirectiveModel.java
@@ -41,6 +41,9 @@ import freemarker.template.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class TopicDirectiveModel implements TemplateDirectiveModel {
/** The shared-variable name this directive registers under. */
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrl_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrl_Test.java
index 9839d9618f..84ac5cfcf8 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrl_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/AssetUrl_Test.java
@@ -34,7 +34,7 @@ import freemarker.template.Template;
/** Tests for the {@code assetUrl(path)} adopter static-asset versioning hook ({@code Builder.adopterAssets}). */
class AssetUrl_Test extends TestBase {
- private static final String PROBE_CRC = "36b350df"; // CRC32 of src/test/resources/adopter-static/js/probe.js
+ private static final String PROBE_CRC = "e7d63129"; // CRC32 of src/test/resources/adopter-static/js/probe.js
private static String render(ConsoleFreemarkerMixin mixin, String ftl) throws Exception {
Configuration cfg = mixin.resolveConfiguration(request());
@@ -68,7 +68,7 @@ class AssetUrl_Test extends TestBase {
"/js/missing.js", "/js/probe.js?v=1", "https://cdn.example.com/x.js");
}
- @Test void a04_devModeMissing_stillPassesThrough() throws Exception {
+ @Test void a04_devModeMissing_stillPassesThrough() {
var m = builder().devMode(true).adopterAssets(AssetUrl_Test.class.getClassLoader(), "adopter-static").build();
var out = new String[1];
var records = LogRecordCapture.quietly(AssetUrlMethodModel.class, () -> out[0] = render(m, "${assetUrl('/js/missing.js')}"));
@@ -82,7 +82,7 @@ class AssetUrl_Test extends TestBase {
assertNull(cfg.getSharedVariable(AssetUrlMethodModel.NAME));
}
- @Test void a06_wrongArity_isRejected() throws Exception {
+ @Test void a06_wrongArity_isRejected() {
var m = builder().adopterAssets(AssetUrl_Test.class.getClassLoader(), "adopter-static").build();
assertThrows(Exception.class, () -> render(m, "${assetUrl()}"));
}
@@ -93,8 +93,13 @@ class AssetUrl_Test extends TestBase {
"first,second", "/js/probe.js?v=" + PROBE_CRC + ",/js/probe.js?v=" + PROBE_CRC);
}
+ @SuppressWarnings({
+ "resource" // The request in the try header is not itself closeable; the response is closed by the try.
+ })
private static RestRequest request() throws Exception {
- MockRestClient.buildLax(Host.class).get("/x").run();
+ try (var c = MockRestClient.buildLax(Host.class); var r = c.get("/x").run()) {
+ assertNotNull(r);
+ }
return Host.CAPTURED.get();
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirective_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirective_Test.java
index 4d94f14c5a..891ea1b995 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirective_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/BridgeDirective_Test.java
@@ -18,14 +18,11 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.junit.jupiter.api.Assertions.*;
-import java.util.*;
-
import org.apache.juneau.*;
import org.apache.juneau.commons.inject.*;
import org.apache.juneau.marshall.marshaller.*;
import org.apache.juneau.rest.mock.classic.*;
import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.console.*;
import org.apache.juneau.rest.server.console.test.*;
import org.apache.juneau.rest.server.servlet.*;
import org.apache.juneau.rest.server.view.*;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardAssetDependencies_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardAssetDependencies_Test.java
index 396bed6221..33dff01802 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardAssetDependencies_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardAssetDependencies_Test.java
@@ -241,6 +241,9 @@ class CardAssetDependencies_Test extends TestBase {
// d - mounting
//-----------------------------------------------------------------------------------------------------------------
+ @SuppressWarnings({
+ "java:S8786" // Test-only; matching /jquery needs backtracking within a short attribute value.
+ })
private static String jqueryUrl(String body) {
var m = Pattern.compile("src=\"([^\"]*/jquery\\.min\\.js[^\"]*)\"").matcher(body);
assertTrue(m.find(), () -> body);
@@ -265,7 +268,7 @@ class CardAssetDependencies_Test extends TestBase {
// e - duplicates against the page's own init=
//-----------------------------------------------------------------------------------------------------------------
- @Test void e01_initJquery_skipsPackJquery() throws Exception {
+ @Test void e01_initJquery_skipsPackJquery() {
var holder = new String[1];
var records = LogRecordCapture.quietly(ToolkitPackRegistry.class, () -> holder[0] = get(Host.class, "dup-init"));
assertEquals(1, records.size(), records::toString);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs_Test.java
index 5929d7862d..2dbc642a62 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardBusAttrs_Test.java
@@ -40,15 +40,18 @@ class CardBusAttrs_Test {
}
@Test void b01_hashWithoutTopic_isIae() {
- var e1 = assertThrows(IllegalArgumentException.class, () -> CardBusAttrs.subscriptions("c", List.of(Map.of("as", "refresh"))));
+ var subs = List.of(Map.of("as", "refresh"));
+ var e1 = assertThrows(IllegalArgumentException.class, () -> CardBusAttrs.subscriptions("c", subs));
assertEquals("<@card id='c'> subscribes entry requires a topic", e1.getMessage());
- var e2 = assertThrows(IllegalArgumentException.class, () -> CardBusAttrs.publications("c", List.of(Map.of("retain", true))));
+ var pubs = List.of(Map.of("retain", true));
+ var e2 = assertThrows(IllegalArgumentException.class, () -> CardBusAttrs.publications("c", pubs));
assertEquals("<@card id='c'> publishes entry requires a topic", e2.getMessage());
}
@Test void b02_nonBooleanRetain_isIae() {
+ var pubs = List.of(Map.of("topic", "t.x", "retain", 1));
var e = assertThrows(IllegalArgumentException.class,
- () -> CardBusAttrs.publications("c", List.of(Map.of("topic", "t.x", "retain", 1))));
+ () -> CardBusAttrs.publications("c", pubs));
assertEquals("<@card id='c'> publishes entry retain must be a boolean (true or false); got '1'", e.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirective_Bus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirective_Bus_Test.java
index 4d3fd7f9d2..d58be40036 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirective_Bus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardDirective_Bus_Test.java
@@ -18,8 +18,6 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.junit.jupiter.api.Assertions.*;
-import java.util.*;
-
import org.apache.juneau.*;
import org.apache.juneau.commons.inject.*;
import org.apache.juneau.marshall.marshaller.*;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRef_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRef_Test.java
index 618679107c..9f473feb4a 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRef_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRef_Test.java
@@ -28,7 +28,6 @@ import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.servlet.*;
import org.apache.juneau.rest.server.view.*;
import org.apache.juneau.rest.server.view.freemarker.*;
-import org.apache.juneau.rest.server.views.*;
import org.junit.jupiter.api.*;
/**
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRequirements_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRequirements_Test.java
index 8256fb72be..9bcf2cf91b 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRequirements_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardRequirements_Test.java
@@ -58,7 +58,8 @@ class CardRequirements_Test extends TestBase {
@Test void a05_forCard_unknownRequires_namesCard() {
var r = CardRequirements.create().build(PACKS);
- var e = assertThrows(IllegalArgumentException.class, () -> r.forCard("html", "box", List.of("ghost")));
+ var arg = List.of("ghost");
+ var e = assertThrows(IllegalArgumentException.class, () -> r.forCard("html", "box", arg));
assertString("Unknown toolkit pack 'ghost' (<@card id='box'> requires=).", e.getMessage());
}
@@ -76,7 +77,9 @@ class CardRequirements_Test extends TestBase {
@Test void a08_forCard_unknownBodyPack_namesCardAndType() {
var r = CardRequirements.create().build(PACKS);
- var e = assertThrows(IllegalArgumentException.class, () -> r.forCard("datatables", "rel", List.of(), List.of("ghost")));
+ var arg2 = List.of("ghost");
+ List<String> noRequires = List.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> r.forCard("datatables", "rel", noRequires, arg2));
assertString("Unknown toolkit pack 'ghost' (<@card id='rel'> type 'datatables' requiredPacks).", e.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Bus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Bus_Test.java
index 630ef1758c..d577b608da 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Bus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Bus_Test.java
@@ -52,12 +52,15 @@ class CardSpec_Bus_Test extends TestBase {
@Test void b01_publishesRejectsPublisher() {
var d = TopicDecl.of("ssc.focus").retain(true).publisher(TopicDecl.Publisher.SCRIPT);
- var e = assertThrows(IllegalArgumentException.class, () -> CardSpec.html("x").publishes(d));
+ var target = CardSpec.html("x");
+ var e = assertThrows(IllegalArgumentException.class, () -> target.publishes(d));
assertEquals("topic 'ssc.focus': publisher is page-level only; a card's publishes may not set it", e.getMessage());
}
@Test void b02_bodyCannotSetWiringKeys() {
- var e = assertThrows(IllegalArgumentException.class, () -> CardSpec.html("x").body("subscribes", java.util.List.of()));
+ var target2 = CardSpec.html("x");
+ var arg3 = java.util.List.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> target2.body("subscribes", arg3));
assertEquals("card 'x': 'subscribes' is a base key; use subscribes(...)", e.getMessage());
}
@@ -72,7 +75,9 @@ class CardSpec_Bus_Test extends TestBase {
}
@Test void b03_wiringRejectsNonMapEntries() {
- var e = assertThrows(IllegalArgumentException.class, () -> CardSpec.html("x").wiring(java.util.List.of("oops"), null));
+ var target3 = CardSpec.html("x");
+ var arg = java.util.List.of("oops");
+ var e = assertThrows(IllegalArgumentException.class, () -> target3.wiring(arg, null));
assertTrue(e.getMessage().contains("must be objects"), e.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Test.java
index a04b3da130..5b1786f4f7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/CardSpec_Test.java
@@ -38,7 +38,8 @@ class CardSpec_Test extends TestBase {
@Test void a02b_bareRefusedWhereSchemaHasNoBare() {
for (var type : List.of("run-view", "terminal")) {
- var ex = assertThrows(IllegalArgumentException.class, () -> CardSpec.of(type, "x").bare(true));
+ var target = CardSpec.of(type, "x");
+ var ex = assertThrows(IllegalArgumentException.class, () -> target.bare(true));
assertTrue(ex.getMessage().contains("card 'x': a " + type + " card does not support bare."), ex.getMessage());
assertFalse(CardSpec.of(type, "x").bare(false).toMap().containsKey("bare"));
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Test.java
index dee5bd8ff6..922ecb252c 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Test.java
@@ -75,57 +75,87 @@ class ChartDef_Test extends TestBase {
}
@Test void a06_errors() {
+ var target = ChartDef.line("t").x("d").series("v", "V");
assertEquals("ChartDef 't' requires exactly one of src(...), data(...) or source(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").x("d").series("v", "V").toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target::toCardSpec).getMessage());
+ var target2 = ChartDef.donut("t").src("/s").data(List.of());
assertEquals("ChartDef 't' requires exactly one of src(...), data(...) or source(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").src("/s").data(List.of()).toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target2::toCardSpec).getMessage());
+ var target3 = ChartDef.line("t").src("/s").x("d");
assertEquals("ChartDef 't' kind 'line' requires x(...) and at least one series(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").src("/s").x("d").toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target3::toCardSpec).getMessage());
+ var target4 = ChartDef.line("t");
assertEquals("ChartDef 't' series tone '9' must be 1-8.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").series("v", "V", 9)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target4.series("v", "V", 9)).getMessage());
+ var target5 = ChartDef.line("t");
assertEquals("ChartDef 't' series tone 'pink' must be 'danger', 'ok' or 'warning'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").series("v", "V", "pink")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target5.series("v", "V", "pink")).getMessage());
+ var target6 = ChartDef.line("t");
assertEquals("ChartDef 't' x type 'date' must be 'category', 'number' or 'time'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").x("d", "date", null)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target6.x("d", "date", null)).getMessage());
+ }
+
+ @Test void a06d_errors_optionLimits() {
+ var target7 = ChartDef.line("t");
assertEquals("ChartDef 't' legend 'top' must be 'bottom', 'right' or 'none'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").legend("top")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target7.legend("top")).getMessage());
+ var target8 = ChartDef.line("t");
assertEquals("ChartDef 't' height '100' is below the minimum '120'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").height(100)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target8.height(100)).getMessage());
+ var target9 = ChartDef.line("t");
assertEquals("ChartDef 't' refreshMs '1000' is below the minimum '5000'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").refreshMs(1000)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target9.refreshMs(1000)).getMessage());
+ var target10 = ChartDef.line("t");
+ var arg4 = List.of();
assertEquals("ChartDef 't' key 'series' has a dedicated method.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").set("series", List.of())).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target10.set("series", arg4)).getMessage());
+ var target11 = ChartDef.line("t");
assertEquals("ChartDef 't' key 'src' has a dedicated method.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").set("src", "/x")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target11.set("src", "/x")).getMessage());
+ }
+
+ @Test void a06e_errors_hrefDataAndRequiredFields() {
+ var target12 = ChartDef.line("t");
+ var target13 = ChartDef.line("t");
+ var target14 = ChartDef.donut("t").data(List.of()).refreshMs(6000);
assertEquals("ChartDef 't' onClick href must be a same-origin path; got 'https://evil.test/x'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").onClickHref("https://evil.test/x")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target12.onClickHref("https://evil.test/x")).getMessage());
assertEquals("ChartDef 't' onClick href must be a same-origin path; got '//evil.test/x'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").onClickHref("//evil.test/x")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target13.onClickHref("//evil.test/x")).getMessage());
assertEquals("ChartDef 't' refreshMs(...) needs src(...); inline data never refreshes.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").data(List.of()).refreshMs(6000).toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target14::toCardSpec).getMessage());
+ var target15 = ChartDef.donut("t");
assertEquals("ChartDef 't' data rows must not be null.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").data(null)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target15.data(null)).getMessage());
+ var target16 = ChartDef.line("t");
assertEquals("ChartDef 't' onClick href must be a same-origin path; got 'null'.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").onClickHref(null)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target16.onClickHref(null)).getMessage());
+ var target17 = ChartDef.donut("t").src("/s").label("s");
assertEquals("ChartDef 't' kind 'donut' requires label(...) and value(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").src("/s").label("s").toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target17::toCardSpec).getMessage());
+ var target18 = ChartDef.donut("t").src("/s").value("n");
assertEquals("ChartDef 't' kind 'donut' requires label(...) and value(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").src("/s").value("n").toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target18::toCardSpec).getMessage());
+ var target19 = ChartDef.donut("t").src("/s").label(" ").value("n");
assertEquals("ChartDef 't' kind 'donut' requires label(...) and value(...).",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.donut("t").src("/s").label(" ").value("n").toCardSpec()).getMessage());
+ assertThrows(IllegalArgumentException.class, target19::toCardSpec).getMessage());
+ var target20 = ChartDef.line("t");
assertEquals("ChartDef 't' series requires a non-blank field.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").series(null, "V")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target20.series(null, "V")).getMessage());
+ var target21 = ChartDef.bar("t");
assertEquals("ChartDef 't' series requires a non-blank field.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.bar("t").series(" ", "V", 2)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target21.series(" ", "V", 2)).getMessage());
+ var target22 = ChartDef.bar("t");
assertEquals("ChartDef 't' series requires a non-blank field.",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.bar("t").series("", "V", "ok")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target22.series("", "V", "ok")).getMessage());
}
@ParameterizedTest
@ValueSource(strings = {"publishes", "subscribes", "template", "bare", "class"})
void a06b_cardLevelKeys_pointAtToCardSpec(String key) {
+ var target23 = ChartDef.line("t");
assertEquals("ChartDef 't' key '" + key + "' is card-level; set it on toCardSpec().",
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").set(key, "x")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target23.set(key, "x")).getMessage());
}
@Test void a06c_wiringGoesOnTheCardSpec() {
@@ -161,7 +191,8 @@ class ChartDef_Test extends TestBase {
}
@Test void b03_raw_requiresOption() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.raw("r").src("/r").toCardSpec());
+ var target24 = ChartDef.raw("r").src("/r");
+ var e = assertThrows(IllegalArgumentException.class, target24::toCardSpec);
assertString("ChartDef 'r' raw(...) requires option(...).", e.getMessage());
}
@@ -186,9 +217,13 @@ class ChartDef_Test extends TestBase {
}
@Test void b07_decorate_badName_isE74() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").decorate("Bad", JsonMap.of()));
+ var target25 = ChartDef.line("t");
+ var arg = JsonMap.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> target25.decorate("Bad", arg));
assertString("E-74: 'Bad' is not a valid decorator name", e.getMessage());
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").decorate("ok", JsonMap.of("use", "x")));
+ var target26 = ChartDef.line("t");
+ var arg2 = JsonMap.of("use", "x");
+ assertThrows(IllegalArgumentException.class, () -> target26.decorate("ok", arg2));
}
@Test void b08_patch_mergesInOrder_byKeyAndById() {
@@ -207,7 +242,8 @@ class ChartDef_Test extends TestBase {
var m = map(ChartDef.line("t").src("/s").x("d").series("v", "V").on("click", "app.pick"));
assertEquals(j("{click:'app.pick'}"), m.get("on"));
assertEquals(j("[{topic:'app.pick',retain:false}]"), m.get("publishes"));
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").on("Click", "app.pick"));
+ var target27 = ChartDef.line("t");
+ var e = assertThrows(IllegalArgumentException.class, () -> target27.on("Click", "app.pick"));
assertString("E-74: 'Click' is not a valid event name", e.getMessage());
}
@@ -220,9 +256,11 @@ class ChartDef_Test extends TestBase {
var m = map(ChartDef.line("t").source(Topics.data("x")).x("d").series("v", "V"));
assertEquals("data:x", m.get("source"));
assertEquals(j("[{topic:'data:x',as:'data'}]"), m.get("subscribes"));
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").src("/s").source("data:x").x("d").series("v", "V").toCardSpec());
+ var target28 = ChartDef.line("t").src("/s").source("data:x").x("d").series("v", "V");
+ var e = assertThrows(IllegalArgumentException.class, target28::toCardSpec);
assertString("ChartDef 't' requires exactly one of src(...), data(...) or source(...).", e.getMessage());
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").source("filter:x"));
+ var target29 = ChartDef.line("t");
+ assertThrows(IllegalArgumentException.class, () -> target29.source("filter:x"));
}
@Test void b13_group_renderer_theme() {
@@ -230,7 +268,8 @@ class ChartDef_Test extends TestBase {
assertEquals("g", m.get("group"));
assertEquals("svg", m.get("renderer"));
assertEquals("juneau-open", m.get("theme"));
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").renderer("webgl"));
+ var target30 = ChartDef.line("t");
+ assertThrows(IllegalArgumentException.class, () -> target30.renderer("webgl"));
}
@Test void b14_largeData_partialFrames_a11y() {
@@ -242,29 +281,36 @@ class ChartDef_Test extends TestBase {
}
@Test void b15_partialFrames_needsSource() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").src("/s").x("d").series("v", "V").partialFrames().toCardSpec());
+ var target31 = ChartDef.line("t").src("/s").x("d").series("v", "V").partialFrames();
+ var e = assertThrows(IllegalArgumentException.class, target31::toCardSpec);
assertString("ChartDef 't' partialFrames() needs source(...).", e.getMessage());
}
@Test void b16_kindOnlyMethods_rejectedOnOtherKinds() {
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").yField("r"));
- assertThrows(IllegalArgumentException.class, () -> ChartDef.bar("t").symbolSizeBy("r"));
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").scale(0, 1));
+ var target32 = ChartDef.line("t");
+ assertThrows(IllegalArgumentException.class, () -> target32.yField("r"));
+ var target33 = ChartDef.bar("t");
+ assertThrows(IllegalArgumentException.class, () -> target33.symbolSizeBy("r"));
+ var target34 = ChartDef.line("t");
+ assertThrows(IllegalArgumentException.class, () -> target34.scale(0, 1));
}
@Test void b17_heatmap_requiresXyValue() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.heatmap("h").src("/h").x("a").toCardSpec());
+ var target35 = ChartDef.heatmap("h").src("/h").x("a");
+ var e = assertThrows(IllegalArgumentException.class, target35::toCardSpec);
assertString("ChartDef 'h' kind 'heatmap' requires x(...), yField(...) and value(...).", e.getMessage());
}
@Test void b18_newKeysAreDedicated() {
+ var target36 = ChartDef.line("t");
for (var k : List.of("source", "helper", "option", "patch", "decorators", "on", "group", "renderer", "theme", "largeData", "partialFrames", "a11y", "maps"))
- assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").set(k, 1), k);
+ assertThrows(IllegalArgumentException.class, () -> target36.set(k, 1), k);
}
@Test void b19_maps_sameOrigin() {
assertEquals(j("{world:'/geo/world.json'}"), map(ChartDef.raw("r").src("/r").option("{}").map("world", "/geo/world.json")).get("maps"));
- assertThrows(IllegalArgumentException.class, () -> ChartDef.raw("r").map("world", "https://x/w.json"));
+ var target37 = ChartDef.raw("r");
+ assertThrows(IllegalArgumentException.class, () -> target37.map("world", "https://x/w.json"));
}
@Test void b20_ofIsGone() {
@@ -272,12 +318,14 @@ class ChartDef_Test extends TestBase {
}
@Test void b21_largeData_thresholdBelowOne_rejected() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").largeData(0));
+ var target38 = ChartDef.line("t");
+ var e = assertThrows(IllegalArgumentException.class, () -> target38.largeData(0));
assertString("ChartDef 't' largeData threshold '0' must be at least 1.", e.getMessage());
}
@Test void b22_group_blank_rejected() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").group(" "));
+ var target39 = ChartDef.line("t");
+ var e = assertThrows(IllegalArgumentException.class, () -> target39.group(" "));
assertString("ChartDef 't' group must be non-blank.", e.getMessage());
}
@@ -289,15 +337,19 @@ class ChartDef_Test extends TestBase {
@Test void b24_decorate_customDecoratorWithBadName_isE74() {
Decorator bad = () -> JsonMap.of("use", "Bad");
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").decorate(bad));
+ var target40 = ChartDef.line("t");
+ var e = assertThrows(IllegalArgumentException.class, () -> target40.decorate(bad));
assertString("E-74: 'Bad' is not a valid decorator name", e.getMessage());
Decorator none = () -> JsonMap.of("x", 1);
- var e2 = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").decorate(none));
+ var target41 = ChartDef.line("t");
+ var e2 = assertThrows(IllegalArgumentException.class, () -> target41.decorate(none));
assertString("E-74: 'null' is not a valid decorator name", e2.getMessage());
}
@Test void b25_decorateWithUse_inArgs_rejected() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.line("t").decorate("app.x", JsonMap.of("use", "y")));
+ var target42 = ChartDef.line("t");
+ var arg3 = JsonMap.of("use", "y");
+ var e = assertThrows(IllegalArgumentException.class, () -> target42.decorate("app.x", arg3));
assertString("ChartDef 't' decorator 'app.x' args must not set 'use'.", e.getMessage());
}
@@ -308,9 +360,11 @@ class ChartDef_Test extends TestBase {
}
@Test void b26_raw_withHelperKeys_rejected() {
- var e = assertThrows(IllegalArgumentException.class, () -> ChartDef.raw("r").src("/s").option("{}").x("d").toCardSpec());
+ var target43 = ChartDef.raw("r").src("/s").option("{}").x("d");
+ var e = assertThrows(IllegalArgumentException.class, target43::toCardSpec);
assertString("ChartDef 'r' raw(...) takes no helper keys (x, y, series, ...); put them in option(...).", e.getMessage());
- assertThrows(IllegalArgumentException.class, () -> ChartDef.raw("r").src("/s").option("{}").series("v", "V").toCardSpec());
+ var target44 = ChartDef.raw("r").src("/s").option("{}").series("v", "V");
+ assertThrows(IllegalArgumentException.class, target44::toCardSpec);
assertNotNull(ChartDef.raw("r").src("/s").option("{}").height(200).toCardSpec());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Treemap_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Treemap_Test.java
index 118f9ffac9..2583b635a7 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Treemap_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ChartDef_Treemap_Test.java
@@ -110,8 +110,8 @@ class ChartDef_Treemap_Test extends TestBase {
var cardKinds = (List<?>)((Map<?,?>)props.get("kind")).get("enum");
var helperProps = (Map<?,?>)((Map<?,?>)props.get("helper")).get("properties");
var helperKinds = (List<?>)((Map<?,?>)helperProps.get("kind")).get("enum");
- assertEquals(new TreeSet<>(ChartDef.KINDS), new TreeSet<>(cardKinds));
- assertEquals(new TreeSet<>(ChartDef.KINDS), new TreeSet<>(helperKinds));
+ assertEquals(new HashSet<>(ChartDef.KINDS), new HashSet<>(cardKinds));
+ assertEquals(new HashSet<>(ChartDef.KINDS), new HashSet<>(helperKinds));
for (var k : List.of("groupBy", "size", "color", "tileFields"))
assertTrue(helperProps.containsKey(k), "schema helper property " + k);
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirective_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirective_Test.java
index dc01176c30..6cb4d84c49 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirective_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleDirective_Test.java
@@ -37,6 +37,8 @@ import org.apache.juneau.rest.server.util.*;
import org.apache.juneau.rest.server.view.*;
import org.apache.juneau.rest.server.view.freemarker.*;
import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.*;
+import org.junit.jupiter.params.provider.*;
/**
* Golden-HTML tests for the {@code <@console>} document-shell directive and its capture slots
@@ -548,7 +550,9 @@ class ConsoleDirective_Test extends TestBase {
}
}
- @Test void t05c_committedResponseOmitsSingleQuotedBodyToken() throws Exception {
+ @ParameterizedTest
+ @ValueSource(strings = {"/body-csrf-single", "/body-csrf-unquoted", "/body-csrf-upper"})
+ void t05c_committedResponseOmitsBodyToken(String path) throws Exception {
var logger = Logger.getLogger(ConsoleDirectiveModel.class.getName());
var records = new ArrayList<LogRecord>();
var handler = new Handler() {
@@ -563,61 +567,7 @@ class ConsoleDirective_Test extends TestBase {
try {
var res = new RecordingResponse();
res.committed = true;
- var body = dispatch(ConsoleHost.class, "/body-csrf-single", res);
- assertFalse(body.contains("spec-tok"), () -> body);
- assertFalse(body.contains("data-juneau-csrf"), () -> body);
- assertTrue(body.contains("data-spec-keep=\"kept\""), () -> body);
- assertNull(res.writtenWhenCacheControlSet);
- assertEquals(1, records.stream().filter(r -> r.getLevel() == Level.FINE).count());
- } finally {
- logger.removeHandler(handler);
- logger.setLevel(oldLevel);
- }
- }
-
- @Test void t05e_committedResponseOmitsUnquotedBodyToken() throws Exception {
- var logger = Logger.getLogger(ConsoleDirectiveModel.class.getName());
- var records = new ArrayList<LogRecord>();
- var handler = new Handler() {
- @Override public void publish(LogRecord r) { records.add(r); }
- @Override public void flush() { /* no buffering */ }
- @Override public void close() { /* nothing to release */ }
- };
- var oldLevel = logger.getLevel();
- logger.setLevel(Level.FINE);
- handler.setLevel(Level.FINE);
- logger.addHandler(handler);
- try {
- var res = new RecordingResponse();
- res.committed = true;
- var body = dispatch(ConsoleHost.class, "/body-csrf-unquoted", res);
- assertFalse(body.contains("spec-tok"), () -> body);
- assertFalse(body.contains("data-juneau-csrf"), () -> body);
- assertTrue(body.contains("data-spec-keep=\"kept\""), () -> body);
- assertNull(res.writtenWhenCacheControlSet);
- assertEquals(1, records.stream().filter(r -> r.getLevel() == Level.FINE).count());
- } finally {
- logger.removeHandler(handler);
- logger.setLevel(oldLevel);
- }
- }
-
- @Test void t05f_committedResponseOmitsUpperCaseBodyToken() throws Exception {
- var logger = Logger.getLogger(ConsoleDirectiveModel.class.getName());
- var records = new ArrayList<LogRecord>();
- var handler = new Handler() {
- @Override public void publish(LogRecord r) { records.add(r); }
- @Override public void flush() { /* no buffering */ }
- @Override public void close() { /* nothing to release */ }
- };
- var oldLevel = logger.getLevel();
- logger.setLevel(Level.FINE);
- handler.setLevel(Level.FINE);
- logger.addHandler(handler);
- try {
- var res = new RecordingResponse();
- res.committed = true;
- var body = dispatch(ConsoleHost.class, "/body-csrf-upper", res);
+ var body = dispatch(ConsoleHost.class, path, res);
assertFalse(body.contains("spec-tok"), () -> body);
assertFalse(body.contains("data-juneau-csrf"), () -> body);
assertTrue(body.contains("data-spec-keep=\"kept\""), () -> body);
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_CardType_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_CardType_Test.java
index 6b0fadc927..08b6ddd66a 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_CardType_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_CardType_Test.java
@@ -27,17 +27,21 @@ class ConsoleFreemarkerMixin_CardType_Test extends TestBase {
@Test void a01_reservedType_throwsE22AtBuilder() {
var b = ConsoleFreemarkerMixin.create();
- var ex = assertThrows(IllegalArgumentException.class, () -> b.cardType(new Named("datatables")));
+ var arg = new Named("datatables");
+ var ex = assertThrows(IllegalArgumentException.class, () -> b.cardType(arg));
assertTrue(ex.getMessage().startsWith("Card type 'datatables' is reserved and cannot be replaced; reserved: '"), ex.getMessage());
}
@Test void a02_badName_throwsE21AtBuilder() {
- assertThrows(IllegalArgumentException.class, () -> ConsoleFreemarkerMixin.create().cardType(new Named("KPI")));
+ var target = ConsoleFreemarkerMixin.create();
+ var arg2 = new Named("KPI");
+ assertThrows(IllegalArgumentException.class, () -> target.cardType(arg2));
}
@Test void a03_duplicate_throwsE20AtBuilder() {
var b = ConsoleFreemarkerMixin.create().cardType(new Named("kpi"));
- assertThrows(IllegalArgumentException.class, () -> b.cardType(new Named("kpi")));
+ var arg3 = new Named("kpi");
+ assertThrows(IllegalArgumentException.class, () -> b.cardType(arg3));
}
@Test void a04_terminalIsRegisteredInStandard() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_Test.java
index a160f80769..2c8d9aa09d 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleFreemarkerMixin_Test.java
@@ -334,7 +334,8 @@ class ConsoleFreemarkerMixin_Test extends TestBase {
}
@Test void g02_requirePacks_unknown_failsAtBuild() {
- var e = assertThrows(IllegalArgumentException.class, () -> ConsoleFreemarkerMixin.create().requirePacks("nope").build());
+ var target = ConsoleFreemarkerMixin.create().requirePacks("nope");
+ var e = assertThrows(IllegalArgumentException.class, target::build);
assertEquals("Unknown toolkit pack 'nope' (requirePacks).", e.getMessage());
}
@@ -343,15 +344,17 @@ class ConsoleFreemarkerMixin_Test extends TestBase {
}
@Test void g04_requirePacks_absentWebJar_isE70() {
- var e = assertThrows(IllegalStateException.class, () -> ConsoleFreemarkerMixin.create().requirePacks("charts")
- .webJarProbe(a -> { throw new IllegalStateException("x"); }).build());
+ var target2 = ConsoleFreemarkerMixin.create().requirePacks("charts")
+ .webJarProbe(a -> { throw new IllegalStateException("x"); });
+ var e = assertThrows(IllegalStateException.class, target2::build);
assertContains("E-70: chart cards need the ECharts WebJar", e.getMessage());
}
@Test void g05_appPackDependsOnEcharts_isOptIn() {
- var e = assertThrows(IllegalStateException.class, () -> ConsoleFreemarkerMixin.create()
+ var target3 = ConsoleFreemarkerMixin.create()
.registerToolkitPack(ToolkitPack.create("app.charts").kind(ToolkitPack.Kind.RUNTIME).js("/a.js").dependsOn("charts").build())
- .webJarProbe(a -> { throw new IllegalStateException("x"); }).build());
+ .webJarProbe(a -> { throw new IllegalStateException("x"); });
+ var e = assertThrows(IllegalStateException.class, target3::build);
assertContains("E-70: ", e.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator_Test.java
index 8aa436a673..a5fdf815d2 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ConsoleTemplateValidator_Test.java
@@ -207,7 +207,7 @@ class ConsoleTemplateValidator_Test extends TestBase {
@Test void cb03_prebuiltSlotMeta_reportsOnlyViewContractVersionAfterGc1() {
// inline-slot-meta is gone at GC-1 (E-28 at render); C1's view-contract-version rule stays (Auto-decision 4).
var f = lint("<@page><@card id=\"t\" type=\"datatables\">{view:{contractVersion:'0',id:'t'}}</@...@page>");
- assertEquals(List.of("view-contract-version"), f.stream().map(x -> x.rule()).toList());
+ assertEquals(List.of("view-contract-version"), f.stream().map(ConsoleTemplateValidator.Finding::rule).toList());
}
@Test void cb05_cardReservedKey() {
@@ -300,10 +300,11 @@ class ConsoleTemplateValidator_Test extends TestBase {
//-----------------------------------------------------------------------------------------------------------------
@Test void i01_hardcodedJuneauAssets_flagged() {
- var f = lint("<link rel=\"stylesheet\" href=\"/rest/home/juneau-views.css\">\n"
- + "<script src='/juneau-console/juneau-console.js?v=1'></script>\n"
- + "<link href=\"/juneau-console/chrome.css\">\n"
- + "<link href=\"themes/juneau-theme-red.css\">");
+ var f = lint("""
+ <link rel="stylesheet" href="/rest/home/juneau-views.css">
+ <script src='/juneau-console/juneau-console.js?v=1'></script>
+ <link href="/juneau-console/chrome.css">
+ <link href="themes/juneau-theme-red.css">""");
assertBean(f, "size", "4");
assertBeans(f, "line,rule", "1,hardcoded-asset-url", "2,hardcoded-asset-url", "3,hardcoded-asset-url", "4,hardcoded-asset-url");
assertTrue(f.get(0).message().contains("'/rest/home/juneau-views.css'"), f.get(0).message());
@@ -401,7 +402,8 @@ class ConsoleTemplateValidator_Test extends TestBase {
}
@Test void w06_nullProbe_rejected() {
- assertThrows(NullPointerException.class, () -> ConsoleTemplateValidator.create().webJarProbe(null));
+ var target = ConsoleTemplateValidator.create();
+ assertThrows(NullPointerException.class, () -> target.webJarProbe(null));
}
@Test void w07_cacheResets_afterProvidedPacks_andRegisterToolkitPack() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec_Test.java
index e022f08bf0..47ced5f031 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DashboardSpec_Test.java
@@ -164,10 +164,10 @@ class DashboardSpec_Test extends TestBase {
@Test void a13_persistOwnedTopics() {
var legend = ChartDef.donut("share").data(ROWS).label("d").value("v").publishLegend();
- DashboardSpec.create("d").panel(legend).persist(PersistSpec.page("a").topics(Topics.legend("share"))).toJson();
+ assertDoesNotThrow(() -> DashboardSpec.create("d").panel(legend).persist(PersistSpec.page("a").topics(Topics.legend("share"))).toJson());
var zoomCard = ChartDef.line("z").data(ROWS).x("d").series("v", "V").publishZoom();
- DashboardSpec.create("d").rail(Rail.left().sections(CardSection.of(zoomCard)))
- .persist(PersistSpec.page("a").topics(Topics.zoom("z"))).toJson();
+ assertDoesNotThrow(() -> DashboardSpec.create("d").rail(Rail.left().sections(CardSection.of(zoomCard)))
+ .persist(PersistSpec.page("a").topics(Topics.zoom("z"))).toJson());
}
@Test void a14_badStatusKey() {
@@ -183,7 +183,8 @@ class DashboardSpec_Test extends TestBase {
@Test void a16_nullPanelId() {
assertEquals("E-77: dashboard 'd': panel 'null' names no card on this page",
e77(() -> DashboardSpec.create("d").panel((String)null).toJson()));
- assertThrows(NullPointerException.class, () -> DashboardSpec.create("d").panel((ChartDef)null));
+ var target = DashboardSpec.create("d");
+ assertThrows(NullPointerException.class, () -> target.panel((ChartDef)null));
}
@Test void a17_duplicateStatusTopic() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef_Test.java
index 095543395c..159cd2962d 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DataSourceDef_Test.java
@@ -72,9 +72,11 @@ class DataSourceDef_Test extends TestBase {
var m = DataSourceDef.create("orders").url("/x").parser("app.csv").builder("app.rows").toMap();
assertEquals("app.csv", m.get("parser"));
assertEquals("app.rows", m.get("builder"));
- var e = assertThrows(IllegalArgumentException.class, () -> DataSourceDef.create("orders").parser("Bad"));
+ var target = DataSourceDef.create("orders");
+ var e = assertThrows(IllegalArgumentException.class, () -> target.parser("Bad"));
assertEquals("E-74: 'Bad' is not a valid parser name", e.getMessage());
- e = assertThrows(IllegalArgumentException.class, () -> DataSourceDef.create("orders").builder("x..y"));
+ var target2 = DataSourceDef.create("orders");
+ e = assertThrows(IllegalArgumentException.class, () -> target2.builder("x..y"));
assertEquals("E-74: 'x..y' is not a valid builder name", e.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType_Test.java
index 12f3bd7b13..3c457621b1 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/DatatablesCardType_Test.java
@@ -100,48 +100,56 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void missingDataUrlOrColumns_throwsE27() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", "{columns:[{key:'a'}]}")));
+ var arg = src("t", "{columns:[{key:'a'}]}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg));
assertEquals("<@card id='t'> type='datatables' requires src= or a body with 'columns' and exactly one of 'dataUrl' or 'rows'.", ex.getMessage());
}
@Test void preBuiltSlotMeta_throwsE28() {
var expected = "<@card id='t'> type='datatables' body is a pre-built SLOT_META envelope; "
+ "remove 'contractVersion', 'layout' and 'view' and author the catalog form.";
+ var arg2 = src("t", "{contractVersion:'1', view:{id:'t', dataUrl:'/x', columns:[]}}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{contractVersion:'1', view:{id:'t', dataUrl:'/x', columns:[]}}")));
+ () -> h.toFragment(arg2));
assertEquals(expected, ex.getMessage());
+ var arg3 = src("t", "{view:{id:'t', dataUrl:'/x', columns:[]}}");
ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{view:{id:'t', dataUrl:'/x', columns:[]}}")));
+ () -> h.toFragment(arg3));
assertEquals(expected, ex.getMessage());
}
@Test void columnMissingKeyAndData_throwsE29() {
+ var arg4 = src("t", "{dataUrl:'/x', columns:[{label:'No key'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{label:'No key'}]}")));
+ () -> h.toFragment(arg4));
assertEquals("<@card id='t'> columns['0'] requires 'key'.", ex.getMessage());
}
@Test void duplicateColumnKey_throwsE30() {
+ var arg5 = src("t", "{dataUrl:'/x', columns:[{key:'a'},{key:'a'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'},{key:'a'}]}")));
+ () -> h.toFragment(arg5));
assertEquals("<@card id='t'> declares column 'a' twice.", ex.getMessage());
}
@Test void contractVersionAnywhere_throwsE31() {
+ var arg6 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{contractVersion:'1', endpoint:'/x'}}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{contractVersion:'1', endpoint:'/x'}}")));
+ () -> h.toFragment(arg6));
assertTrue(ex.getMessage().contains("sets contractVersion; remove it"), ex.getMessage());
}
@Test void unknownSearchType_throwsE32() {
+ var arg7 = src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'bogus'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'bogus'}]}")));
+ () -> h.toFragment(arg7));
assertTrue(ex.getMessage().startsWith("<@card id='t'> column 'a' searchType 'bogus' is unknown; known: '"), ex.getMessage());
}
@Test void unknownSearchOperator_throwsE33() {
+ var arg8 = src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'text', searchOperators:['$bogus']}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'text', searchOperators:['$bogus']}]}")));
+ () -> h.toFragment(arg8));
assertTrue(ex.getMessage().startsWith("<@card id='t'> column 'a' searchOperators names unknown operator '$bogus'; known: '"),
ex.getMessage());
}
@@ -154,40 +162,46 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void bulkWithoutSelection_throwsE34() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t",
- "{dataUrl:'/x', columns:[{key:'a'}], bulk:{actions:[{id:'x',endpoint:'/x'}]}}")));
+ var arg9 = src("t",
+ "{dataUrl:'/x', columns:[{key:'a'}], bulk:{actions:[{id:'x',endpoint:'/x'}]}}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg9));
assertEquals("<@card id='t'> sets bulk without selection.", ex.getMessage());
}
@Test void aggregateEndpointWithFieldToken_throwsE35_noCardPrefix() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t",
+ var arg10 = src("t",
"{dataUrl:'/x', columns:[{key:'a'}], selection:{rowIdField:'a'}, "
- + "bulk:{actions:[{id:'abort', endpoint:'/rest/{id}/abort', mode:'aggregate'}]}}")));
+ + "bulk:{actions:[{id:'abort', endpoint:'/rest/{id}/abort', mode:'aggregate'}]}}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg10));
assertEquals("Bulk action 'abort' has mode 'aggregate' but its endpoint '/rest/{id}/abort' contains a "
+ "{field} token; aggregate endpoints receive {ids} in the body.", ex.getMessage());
}
@Test void unknownColumnKey_throwsE36() {
+ var arg11 = src("t", "{dataUrl:'/x', columns:[{key:'a', bogus:1}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a', bogus:1}]}")));
+ () -> h.toFragment(arg11));
assertTrue(ex.getMessage().startsWith("<@card id='t'> column 'a' has unknown key 'bogus'; known: '"), ex.getMessage());
}
@Test void ribbonUnknownType_isRejected_columnSearchToggle() {
+ var arg12 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'columnSearchToggle'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'columnSearchToggle'}]}")));
+ () -> h.toFragment(arg12));
assertTrue(ex.getMessage().startsWith("<@card id='t'> RibbonItem type 'columnSearchToggle' is not one of '"), ex.getMessage());
}
@Test void ribbonUnknownKey_isRejected() {
+ var arg13 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'refresh', bogus:1}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'refresh', bogus:1}]}")));
+ () -> h.toFragment(arg13));
assertEquals("<@card id='t'> RibbonItem refresh does not accept 'bogus'.", ex.getMessage());
}
@Test void ribbonExportWithoutButtons_isRejected() {
+ var arg14 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'export'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'export'}]}")));
+ () -> h.toFragment(arg14));
assertEquals("<@card id='t'> RibbonItem export requires at least one button.", ex.getMessage());
}
@@ -197,14 +211,16 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void ribbonDividerWithGroup_isRejected() {
+ var arg15 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'divider', group:'g'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'divider', group:'g'}]}")));
+ () -> h.toFragment(arg15));
assertEquals("<@card id='t'> RibbonItem divider does not accept 'group'.", ex.getMessage());
}
@Test void ribbonVisibleWhen_isChecked() {
+ var arg16 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'refresh', visibleWhen:5}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'refresh', visibleWhen:5}]}")));
+ () -> h.toFragment(arg16));
assertTrue(ex.getMessage().contains("visibleWhen must be a list"), ex.getMessage());
}
@@ -220,26 +236,30 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void ribbonBadOptionGroupMemberKey_isRejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t",
- "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'optionGroup', id:'g', options:[{id:'a', persist:true}]}]}")));
+ var arg17 = src("t",
+ "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'optionGroup', id:'g', options:[{id:'a', persist:true}]}]}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg17));
assertEquals("<@card id='t'> RibbonItem optionGroup 'g' member 'a' does not accept 'persist'.", ex.getMessage());
}
@Test void ribbonNonMapItem_isRejected() {
+ var arg18 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:['refresh']}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:['refresh']}")));
+ () -> h.toFragment(arg18));
assertEquals("<@card id='t'> ribbon each item must be an object.", ex.getMessage());
}
@Test void ribbonMissingType_saysSo() {
+ var arg19 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{id:'x'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{id:'x'}]}")));
+ () -> h.toFragment(arg19));
assertTrue(ex.getMessage().startsWith("<@card id='t'> RibbonItem requires a 'type'"), ex.getMessage());
}
@Test void ribbonOptionWithoutScope_isRejected() {
+ var arg20 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'option', id:'o', value:'v'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], ribbon:[{type:'option', id:'o', value:'v'}]}")));
+ () -> h.toFragment(arg20));
assertEquals("<@card id='t'> RibbonItem option 'o' sets neither column nor param.", ex.getMessage());
}
@@ -276,27 +296,33 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void inlineRows_andDataUrl_throwsE27() {
+ var arg21 = src("t", "{dataUrl:'/d', rows:[], columns:[{key:'a'}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/d', rows:[], columns:[{key:'a'}]}")));
+ () -> h.toFragment(arg21));
assertTrue(ex.getMessage().contains("exactly one of 'dataUrl' or 'rows'"), ex.getMessage());
}
@Test void missingColumns_throwsE27() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", "{dataUrl:'/d'}")));
+ var arg22 = src("t", "{dataUrl:'/d'}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg22));
assertTrue(ex.getMessage().contains("'columns'"), ex.getMessage());
}
@Test void inlineRows_malformed_rejected() {
- assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", "{rows:'nope', columns:[{key:'a'}]}")));
- assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", "{rows:[1], columns:[{key:'a'}]}")));
+ var arg23 = src("t", "{rows:'nope', columns:[{key:'a'}]}");
+ assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg23));
+ var arg24 = src("t", "{rows:[1], columns:[{key:'a'}]}");
+ assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg24));
}
@Test void inlineRows_withServerModeOrPolling_rejected() {
+ var arg25 = src("t", "{rows:[], dataMode:'server', columns:[{key:'a'}]}");
var server = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{rows:[], dataMode:'server', columns:[{key:'a'}]}")));
+ () -> h.toFragment(arg25));
assertTrue(server.getMessage().contains("dataMode"), server.getMessage());
+ var arg26 = src("t", "{rows:[], pollIntervalMs:5000, columns:[{key:'a'}]}");
var poll = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{rows:[], pollIntervalMs:5000, columns:[{key:'a'}]}")));
+ () -> h.toFragment(arg26));
assertTrue(poll.getMessage().contains("pollIntervalMs"), poll.getMessage());
assertDoesNotThrow(() -> h.toFragment(src("t", "{rows:[], dataMode:'client', columns:[{key:'a'}]}")));
}
@@ -308,13 +334,15 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void bareUrlBody_isE25() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", "/rest/t")));
+ var arg27 = src("t", "/rest/t");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg27));
assertEquals("<@card id='t'> type='datatables' requires a JSON5 object body; got '/rest/t'.", ex.getMessage());
}
@Test void customOperatorNotAnObject_throws() {
+ var arg28 = src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'text', customOperators:['x']}]}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a', searchType:'text', customOperators:['x']}]}")));
+ () -> h.toFragment(arg28));
assertTrue(ex.getMessage().contains("each customOperator must be an object."), ex.getMessage());
}
@@ -379,14 +407,16 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void a05_jobLogRegion_withoutConfig_isRejected() {
+ var arg29 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{endpoint:'/x/{id}', region:{id:'job', populate:'job-log'}}}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{endpoint:'/x/{id}', region:{id:'job', populate:'job-log'}}}")));
+ () -> h.toFragment(arg29));
assertEquals("<@card id='t'> type='datatables' detail.region 'job' with populate 'job-log' requires a 'config' object.", ex.getMessage());
}
@Test void a06_jobLogRegion_badConfig_namesTheRegion() {
+ var arg30 = src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{endpoint:'/x/{id}', region:{id:'job', populate:'job-log', config:{submit:{endpoint:'/e',action:'a',keyUrl:'/k'},urlParam:'j'}}}}");
var ex = assertThrows(IllegalArgumentException.class,
- () -> h.toFragment(src("t", "{dataUrl:'/x', columns:[{key:'a'}], detail:{endpoint:'/x/{id}', region:{id:'job', populate:'job-log', config:{submit:{endpoint:'/e',action:'a',keyUrl:'/k'},urlParam:'j'}}}}")));
+ () -> h.toFragment(arg30));
assertEquals("<@card id='t'> type='datatables' detail.region: JobLogRegion 'job' urlParam is not allowed in a row-detail region; a page reload does not reattach.", ex.getMessage());
}
@@ -415,7 +445,8 @@ class DatatablesCardType_Test extends TestBase {
}
private void refused(String body, String msg) {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t", body)));
+ var arg31 = src("t", body);
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg31));
assertEquals("<@card id='t'> " + msg, ex.getMessage());
}
@@ -542,8 +573,9 @@ class DatatablesCardType_Test extends TestBase {
}
@Test void quickStats_contractVersion_e31Wins() {
- var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(src("t",
- "{dataUrl:'/x', columns:[{key:'id'}], quickStats:{contractVersion:'1', items:[{id:'a', type:'chart'}]}}")));
+ var arg32 = src("t",
+ "{dataUrl:'/x', columns:[{key:'id'}], quickStats:{contractVersion:'1', items:[{id:'a', type:'chart'}]}}");
+ var ex = assertThrows(IllegalArgumentException.class, () -> h.toFragment(arg32));
assertTrue(ex.getMessage().contains("'quickStats' sets contractVersion"), ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Decorators_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Decorators_Test.java
index 842fa05938..cc384de8c0 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Decorators_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Decorators_Test.java
@@ -56,7 +56,8 @@ class Decorators_Test extends TestBase {
@Test void a04_markers_rejects() {
assertThrows(IllegalArgumentException.class, () -> Markers.from("https://evil/x"));
assertThrows(IllegalArgumentException.class, () -> Markers.source("filter:x"));
- assertThrows(IllegalArgumentException.class, () -> Markers.now("x").style("wavy"));
+ var target = Markers.now("x");
+ assertThrows(IllegalArgumentException.class, () -> target.style("wavy"));
}
@Test void a05_bands() {
@@ -64,13 +65,15 @@ class Decorators_Test extends TestBase {
Bands.from("/rest/outages").start("from").end("to").label("Outage").toJson());
assertEquals(j("{use:'bands',auto:'gaps',label:'No data'}"), Bands.gaps().label("No data").toJson());
assertEquals(j("{use:'bands',auto:'gaps',minGap:2}"), Bands.gaps().minGap(2).toJson());
- assertThrows(IllegalArgumentException.class, () -> Bands.gaps().minGap(0));
+ var target2 = Bands.gaps();
+ assertThrows(IllegalArgumentException.class, () -> target2.minGap(0));
}
@Test void a06_thresholds() {
assertEquals(j("{use:'thresholds',values:[{y:500,label:'SLO',tone:'danger'}]}"),
Thresholds.at(500).label("SLO").tone("danger").toJson());
- assertThrows(IllegalArgumentException.class, () -> Thresholds.at(1).tone("pink"));
+ var target3 = Thresholds.at(1);
+ assertThrows(IllegalArgumentException.class, () -> target3.tone("pink"));
}
@Test void a07_annotations() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Derived_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Derived_Test.java
index ce4dd62fca..c8e96b763e 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Derived_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Derived_Test.java
@@ -43,14 +43,18 @@ class Derived_Test extends TestBase {
}
@Test void a02_errors() {
- var e = assertThrows(IllegalArgumentException.class, () -> Derived.from("a").transform("Bad", null));
+ var target = Derived.from("a");
+ var e = assertThrows(IllegalArgumentException.class, () -> target.transform("Bad", null));
assertEquals("E-74: 'Bad' is not a valid transform name", e.getMessage());
- var s = assertThrows(IllegalStateException.class, () -> Derived.from("a").toMap());
+ var target2 = Derived.from("a");
+ var s = assertThrows(IllegalStateException.class, target2::toMap);
assertEquals("Derived.from('a'): as(id) not called", s.getMessage());
- e = assertThrows(IllegalArgumentException.class, () -> Derived.from("a").as("a"));
+ var target3 = Derived.from("a");
+ e = assertThrows(IllegalArgumentException.class, () -> target3.as("a"));
assertEquals("E-76: data source 'a': a derived source cannot read its own topic", e.getMessage());
- e = assertThrows(IllegalArgumentException.class, () -> Derived.from("a")
- .params(Subscription.to("app.x").as("refresh")).as("b").toMap());
+ var target4 = Derived.from("a")
+ .params(Subscription.to("app.x").as("refresh")).as("b");
+ e = assertThrows(IllegalArgumentException.class, target4::toMap);
assertEquals("E-76: data source 'b': subscription to 'app.x' has role 'refresh'; "
+ "a derived source accepts params", e.getMessage());
assertThrows(IllegalArgumentException.class, () -> Derived.from("bad id"));
@@ -64,7 +68,8 @@ class Derived_Test extends TestBase {
assertEquals("{\"field\":\"x\"}", ((JsonMap)((List<?>)m.get("transforms")).get(0)).get("args").toString());
((JsonMap)((List<?>)m.get("transforms")).get(0)).put("use", "zzz");
assertEquals("filter", ((JsonMap)((List<?>)d.toMap().get("transforms")).get(0)).get("use"));
- var e = assertThrows(IllegalArgumentException.class, () -> Derived.from("a").params((Subscription)null));
+ var target5 = Derived.from("a");
+ var e = assertThrows(IllegalArgumentException.class, () -> target5.params((Subscription)null));
assertEquals("E-76: data source 'a': subscription is null", e.getMessage());
}
@@ -72,7 +77,8 @@ class Derived_Test extends TestBase {
var msg = "E-76: data source '%s': id must match ^[A-Za-z][A-Za-z0-9_-]{0,63}$";
assertEquals(msg.formatted("1st"), assertThrows(IllegalArgumentException.class, () -> Derived.from("1st"))
.getMessage());
+ var target6 = Derived.from("a");
assertEquals(msg.formatted("a.b"),
- assertThrows(IllegalArgumentException.class, () -> Derived.from("a").as("a.b")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target6.as("a.b")).getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCard_Parity_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCard_Parity_Test.java
index 7ea33efbd2..9f809ea90c 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCard_Parity_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/JobLogCard_Parity_Test.java
@@ -22,7 +22,6 @@ import java.util.*;
import org.apache.juneau.*;
import org.apache.juneau.rest.server.console.*;
-import org.junit.jupiter.api.*;
import org.junit.jupiter.params.*;
import org.junit.jupiter.params.provider.*;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Bus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Bus_Test.java
index 6acc0283b9..5aad7f3476 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Bus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Bus_Test.java
@@ -67,23 +67,26 @@ class PageCapture_Bus_Test extends TestBase {
@Test void b01_retainConflict_isE46() {
var cap = new PageCapture();
cap.addTopic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER).toMap(), "PageSpec.topic");
+ var arg = TopicDecl.of("ops.jobs").retain(false).publisher(Publisher.SERVER).toMap();
var e = assertThrows(IllegalArgumentException.class,
- () -> cap.addTopic(TopicDecl.of("ops.jobs").retain(false).publisher(Publisher.SERVER).toMap(), "<@topic>"));
+ () -> cap.addTopic(arg, "<@topic>"));
assertEquals("topic 'ops.jobs' is declared with retain=false here and retain=true at PageSpec.topic", e.getMessage());
}
@Test void b03_publisherConflict_isE46() {
var cap = new PageCapture();
cap.addTopic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER).toMap(), "PageSpec.topic");
+ var arg2 = TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SCRIPT).toMap();
var e = assertThrows(IllegalArgumentException.class,
- () -> cap.addTopic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SCRIPT).toMap(), "<@topic>"));
+ () -> cap.addTopic(arg2, "<@topic>"));
assertEquals("topic 'ops.jobs' is declared with publisher=script here and publisher=server at PageSpec.topic", e.getMessage());
}
@Test void b02_duplicateBridge_isE51() {
var cap = new PageCapture();
cap.addBridge(BridgeDecl.sse("ops", "/s").downstream("ops.a").toMap());
- var e = assertThrows(IllegalArgumentException.class, () -> cap.addBridge(BridgeDecl.sse("ops", "/t").downstream("ops.b").toMap()));
+ var arg3 = BridgeDecl.sse("ops", "/t").downstream("ops.b").toMap();
+ var e = assertThrows(IllegalArgumentException.class, () -> cap.addBridge(arg3));
assertEquals("bridge 'ops': duplicate id", e.getMessage());
}
@@ -91,7 +94,8 @@ class PageCapture_Bus_Test extends TestBase {
var cap = new PageCapture();
cap.addTopic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER).toMap(), "PageSpec.topic");
// R-11: a server topic that no bridge carries.
- var e = assertThrows(IllegalArgumentException.class, () -> cap.checkWiring(CardTypeRegistry.standard()));
+ var arg4 = CardTypeRegistry.standard();
+ var e = assertThrows(IllegalArgumentException.class, () -> cap.checkWiring(arg4));
assertEquals("topic 'ops.jobs' is declared publisher=server but no bridge carries it downstream", e.getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Merge_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Merge_Test.java
index c797a75ce2..83a228f08f 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Merge_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageCapture_Merge_Test.java
@@ -58,7 +58,7 @@ class PageCapture_Merge_Test extends TestBase {
assertEquals("PageSpec sets tab='slo' and <@page tab='activity'> also sets it; set it in one place.", ex.getMessage());
}
- @Test void a05_mergeTheme_conflictRejected() throws TemplateModelException {
+ @Test void a05_mergeTheme_conflictRejected() {
var cap = new PageCapture();
cap.theme("light-red"); // As a page spec seeds it.
var ex = assertThrows(TemplateModelException.class, () -> cap.mergeTheme("open"));
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BadgesFacts_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BadgesFacts_Test.java
index 3aee989e81..f5677608b3 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BadgesFacts_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BadgesFacts_Test.java
@@ -201,14 +201,18 @@ class PageSpec_BadgesFacts_Test extends TestBase {
}
@Test void c01_badLeafType_isRejected() {
+ var target = PageSpec.create();
+ Map<String,Object> facts = Map.of("owner", new java.util.concurrent.atomic.AtomicInteger(1));
var e = assertThrows(IllegalArgumentException.class,
- () -> PageSpec.create().facts(Map.of("owner", new java.util.concurrent.atomic.AtomicInteger(1))));
+ () -> target.facts(facts));
assertTrue(e.getMessage().contains("Fact 'owner' has unsupported value type 'AtomicInteger'"), e.getMessage());
}
@Test void c02_nestedLeafType_namesDottedPath() {
+ var target2 = PageSpec.create();
+ Map<String,Object> facts = Map.of("viewer", Map.of("roles", List.of("oncall", 42)));
var e = assertThrows(IllegalArgumentException.class,
- () -> PageSpec.create().facts(Map.of("viewer", Map.of("roles", List.of("oncall", 42)))));
+ () -> target2.facts(facts));
assertTrue(e.getMessage().contains("Fact 'viewer.roles'"), e.getMessage());
}
@@ -218,7 +222,9 @@ class PageSpec_BadgesFacts_Test extends TestBase {
}
@Test void c04_badgeValidate_runsAtSetter() {
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().badge(BadgeDef.create("x")));
+ var target3 = PageSpec.create();
+ var arg = BadgeDef.create("x");
+ assertThrows(IllegalArgumentException.class, () -> target3.badge(arg));
}
@Test void d01_navScopedBadge_unknownNavKey_isE68() throws Exception {
@@ -288,8 +294,10 @@ class PageSpec_BadgesFacts_Test extends TestBase {
}
@Test void e03_nullRules_areRejected() {
- assertThrows(IllegalArgumentException.class, () -> CardSpec.html("c").visibleWhen((VisibilityRule[])null));
- assertThrows(IllegalArgumentException.class, () -> CardSpec.html("c").visibleWhen((VisibilityRule)null));
+ var target4 = CardSpec.html("c");
+ assertThrows(IllegalArgumentException.class, () -> target4.visibleWhen((VisibilityRule[])null));
+ var target5 = CardSpec.html("c");
+ assertThrows(IllegalArgumentException.class, () -> target5.visibleWhen((VisibilityRule)null));
}
@SuppressWarnings("unchecked")
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BrowserCorpus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BrowserCorpus_Test.java
index a2c2c52c4f..c1d9ec6cfe 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BrowserCorpus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_BrowserCorpus_Test.java
@@ -44,6 +44,9 @@ class PageSpec_BrowserCorpus_Test extends TestBase {
private static final Path DIR = Path.of("..", "juneau-rest-server-views", "src", "test", "resources", "pagespec-corpus");
+ @SuppressWarnings({
+ "resource" // The request in the try header is not itself closeable; the response is closed by the try.
+ })
private static void check(String caseName) throws Exception {
String html;
try (var c = MockRestClient.buildLax(PageSpec_Parity_Test.Host.class); var rsp = c.get("/spec/" + caseName).run()) {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Bus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Bus_Test.java
index 60b76b75e2..f0d73e44e3 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Bus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Bus_Test.java
@@ -18,8 +18,6 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.junit.jupiter.api.Assertions.*;
-import java.util.*;
-
import org.apache.juneau.*;
import org.apache.juneau.marshall.collections.*;
import org.apache.juneau.marshall.marshaller.*;
@@ -71,40 +69,46 @@ class PageSpec_Bus_Test extends TestBase {
@Test void b01_retainConflict_isE46() {
var spec = PageSpec.create().topic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER));
+ var conflict = TopicDecl.of("ops.jobs").retain(false).publisher(Publisher.SERVER);
var e = assertThrows(IllegalArgumentException.class,
- () -> spec.topic(TopicDecl.of("ops.jobs").retain(false).publisher(Publisher.SERVER)));
+ () -> spec.topic(conflict));
assertEquals("topic 'ops.jobs' is declared with retain=false here and retain=true at PageSpec.topic", e.getMessage());
}
@Test void b03_publisherConflict_isE46() {
var spec = PageSpec.create().topic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER));
+ var conflict = TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SCRIPT);
var e = assertThrows(IllegalArgumentException.class,
- () -> spec.topic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SCRIPT)));
+ () -> spec.topic(conflict));
assertEquals("topic 'ops.jobs' is declared with publisher=script here and publisher=server at PageSpec.topic", e.getMessage());
}
@Test void b04_servletSession_withoutRequest_failsClearly() {
+ var bridge = BridgeDecl.sse("ops", "servlet:/juneau-bus/session").downstream("ops.jobs");
var e = assertThrows(IllegalArgumentException.class,
- () -> PageSpec.resolvedBridge(BridgeDecl.sse("ops", "servlet:/juneau-bus/session").downstream("ops.jobs"), null));
+ () -> PageSpec.resolvedBridge(bridge, null));
assertEquals("BridgeDecl 'ops' session 'servlet:/juneau-bus/session' needs a request to resolve.", e.getMessage());
}
@Test void b02_duplicateBridge_isE51() {
var spec = PageSpec.create().bridge(BridgeDecl.sse("ops", "/s").downstream("ops.a"));
- var e = assertThrows(IllegalArgumentException.class, () -> spec.bridge(BridgeDecl.sse("ops", "/t").downstream("ops.b")));
+ var dup = BridgeDecl.sse("ops", "/t").downstream("ops.b");
+ var e = assertThrows(IllegalArgumentException.class, () -> spec.bridge(dup));
assertEquals("bridge 'ops': duplicate id", e.getMessage());
}
@Test void c01_earlyR10_whenNoPageTemplate() {
var spec = PageSpec.create().html("b", "<p/>", c -> c.subscribes(Subscription.to("ssc.focus").as("refresh")));
- var e = assertThrows(IllegalArgumentException.class, () -> spec.checkWiringEarly(CardTypeRegistry.standard(), null));
+ var reg = CardTypeRegistry.standard();
+ var e = assertThrows(IllegalArgumentException.class, () -> spec.checkWiringEarly(reg, null));
assertTrue(e.getMessage().startsWith("card 'b' subscribes to 'ssc.focus' but nothing publishes it"), e.getMessage());
}
@Test void c02_earlyR10_seesTableRibbonTarget() {
var spec = PageSpec.create().table(TableSpec.create("changes").dataUrl("/rest/changes/data").columns(Column.create("pod"))
.ribbon(RibbonItem.refresh().title("Refresh tasks").target("nope")));
- var e = assertThrows(IllegalArgumentException.class, () -> spec.checkWiringEarly(CardTypeRegistry.standard(), null));
+ var reg = CardTypeRegistry.standard();
+ var e = assertThrows(IllegalArgumentException.class, () -> spec.checkWiringEarly(reg, null));
assertEquals("topic 'cmd:nope' names card 'nope', which is not on this page", e.getMessage());
}
@@ -118,9 +122,15 @@ class PageSpec_Bus_Test extends TestBase {
}
}
+ @SuppressWarnings({
+ "resource" // The request in the try header is not itself closeable; the response is closed by the try.
+ })
@Test void c04_servletSession_resolvesBeforeEarlyCheck() throws Exception {
- MockRestClient.buildLax(Host.class).get("/x").run();
- var req = Host.CAPTURED.get();
+ RestRequest req;
+ try (var c = MockRestClient.buildLax(Host.class); var r = c.get("/x").run()) {
+ assertNotNull(r);
+ req = Host.CAPTURED.get();
+ }
var spec = PageSpec.create()
.topic(TopicDecl.of("ops.jobs").retain(true).publisher(Publisher.SERVER))
.bridge(BridgeDecl.sse("ops", "servlet:/juneau-bus/session").downstream("ops.jobs"))
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Cards_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Cards_Test.java
index 18f94271f6..be022b2d5a 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Cards_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Cards_Test.java
@@ -69,7 +69,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a05_table_validatesImmediately() {
var t = TableSpec.create("slo").columns(Column.create("pod"));
- var ex = assertThrows(IllegalStateException.class, () -> PageSpec.create().table(t));
+ var target = PageSpec.create();
+ var ex = assertThrows(IllegalStateException.class, () -> target.table(t));
assertEquals("TableSpec 'slo' requires dataUrl.", ex.getMessage());
}
@@ -85,7 +86,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a07_table_duplicateId_rejected() {
var spec = PageSpec.create().table(table("slo"));
- var ex = assertThrows(IllegalArgumentException.class, () -> spec.table(table("slo")));
+ var arg = table("slo");
+ var ex = assertThrows(IllegalArgumentException.class, () -> spec.table(arg));
assertEquals("PageSpec card id 'slo' is already declared.", ex.getMessage());
}
@@ -106,17 +108,20 @@ class PageSpec_Cards_Test extends TestBase {
}
@Test void a11_html_nullMarkup_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().html("intro", null));
+ var target2 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target2.html("intro", null));
assertEquals("PageSpec.html id 'intro' requires a non-null markup.", ex.getMessage());
}
@Test void a12_html_consumerSettingSrc_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().html("intro", "<p/>", c -> c.src("/x")));
+ var target3 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target3.html("intro", "<p/>", c -> c.src("/x")));
assertEquals("PageSpec.html id 'intro' sets a markup body; its Consumer<CardSpec> must not also set src or template.", ex.getMessage());
}
@Test void a13_html_consumerSettingTemplate_rejected() {
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().html("intro", "<p/>", c -> c.template("t")));
+ var target4 = PageSpec.create();
+ assertThrows(IllegalArgumentException.class, () -> target4.html("intro", "<p/>", c -> c.template("t")));
}
@Test void a14_card_registeredCustomType_accepted() {
@@ -131,21 +136,29 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a16_card_removedType_rejected() {
for (var type : List.of("js", "json", "calendar")) {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.of(type, "x")));
+ var target5 = PageSpec.create();
+ var arg2 = CardSpec.of(type, "x");
+ var ex = assertThrows(IllegalArgumentException.class, () -> target5.card(arg2));
assertEquals("PageSpec.card type '" + type + "' was removed in 10.0.0; use PageSpec.html(...) with a markup/template, or a registered card type.", ex.getMessage());
}
}
@Test void a17_card_dedicatedMethodTypes_rejected() {
- var h = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.html("x")));
+ var target6 = PageSpec.create();
+ var arg3 = CardSpec.html("x");
+ var h = assertThrows(IllegalArgumentException.class, () -> target6.card(arg3));
assertEquals("PageSpec.card type 'html' has a dedicated method; use PageSpec.html(...).", h.getMessage());
- var d = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.of("datatables", "x")));
+ var target7 = PageSpec.create();
+ var arg4 = CardSpec.of("datatables", "x");
+ var d = assertThrows(IllegalArgumentException.class, () -> target7.card(arg4));
assertEquals("PageSpec.card type 'datatables' has a dedicated method; use PageSpec.table(...).", d.getMessage());
}
@Test void a18_card_reservedWithoutHandler_rejected() {
for (var type : List.of("run-view")) {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.of(type, "x")));
+ var target8 = PageSpec.create();
+ var arg5 = CardSpec.of(type, "x");
+ var ex = assertThrows(IllegalArgumentException.class, () -> target8.card(arg5));
assertEquals("PageSpec.card type '" + type + "' is reserved and has no card-type handler; it cannot be built with PageSpec.", ex.getMessage());
}
}
@@ -195,41 +208,52 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a25_applyTo_duplicateOfAuthoredCard_rejected() throws Exception {
var cap = new PageCapture();
cap.addCard(CardSpec.html("intro"), null);
+ var target18 = PageSpec.create().html("intro", "<p/>");
var ex = assertThrows(freemarker.template.TemplateModelException.class,
- () -> PageSpec.create().html("intro", "<p/>").applyTo(cap, MODEL));
+ () -> target18.applyTo(cap, MODEL));
assertTrue(ex.getMessage().contains("<@card id='intro'> duplicates an existing card id."));
}
@Test void a26_addCard_afterBuiltCardWithSameId_rejected() throws Exception {
var cap = new PageCapture();
PageSpec.create().html("intro", "<p/>").applyTo(cap, MODEL);
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> cap.addCard(CardSpec.html("intro"), null));
+ var arg10 = CardSpec.html("intro");
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> cap.addCard(arg10, null));
assertTrue(ex.getMessage().contains("<@card id='intro'> duplicates an existing card id."));
}
@Test void a27_bodyAttr_badName_rejected() {
for (var name : new String[]{null, "", "1a", "a b", "a=\"b", "a>"}) {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().bodyAttr(name, "v"));
+ var target9 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target9.bodyAttr(name, "v"));
assertEquals("PageSpec.bodyAttr name '" + name + "' must match [A-Za-z_:][-A-Za-z0-9_:.]*.", ex.getMessage());
}
}
@Test void a28_csrf_nullToken_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().csrf(null, "X"));
+ var target10 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target10.csrf(null, "X"));
assertEquals("PageSpec.csrf requires a non-null token.", ex.getMessage());
}
@Test void a29_card_nullCardOrType_rejected() {
+ var target11 = PageSpec.create();
assertEquals("PageSpec.card requires a non-null card.",
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card((CardSpec)null)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target11.card((CardSpec)null)).getMessage());
+ var target12 = PageSpec.create();
+ var arg6 = CardSpec.of(null, "x");
assertEquals("PageSpec.card id 'x' requires a non-blank type.",
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.of(null, "x"))).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target12.card(arg6)).getMessage());
}
@Test void a30_table_consumerSettingSrcOrTemplate_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().table(table("slo"), c -> c.src("/x")));
+ var target13 = PageSpec.create();
+ var arg7 = table("slo");
+ var ex = assertThrows(IllegalArgumentException.class, () -> target13.table(arg7, c -> c.src("/x")));
assertEquals("PageSpec.table id 'slo' sets src or template; the table supplies the card's data.", ex.getMessage());
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().table(table("slo"), c -> c.template("t")));
+ var target14 = PageSpec.create();
+ var arg8 = table("slo");
+ assertThrows(IllegalArgumentException.class, () -> target14.table(arg8, c -> c.template("t")));
}
@Test void a31_copy_isIndependent() {
@@ -278,8 +302,10 @@ class PageSpec_Cards_Test extends TestBase {
}
@Test void a35_applyTo_cardsWithoutCardModel_rejected() {
+ var target19 = PageSpec.create().html("intro", "<p/>");
+ var arg11 = new PageCapture();
var ex = assertThrows(freemarker.template.TemplateModelException.class,
- () -> PageSpec.create().html("intro", "<p/>").applyTo(new PageCapture(), null));
+ () -> target19.applyTo(arg11, null));
assertTrue(ex.getMessage().contains("PageSpec cards need the console card directive"), ex.getMessage());
}
@@ -302,13 +328,15 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a37_applyTo_invalidChartCard_rejectedByHandler() {
var spec = PageSpec.create().card(CardSpec.of("chart", "trend").src("/s").body("kind", "line"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg12 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg12, MODEL));
assertTrue(ex.getMessage().contains("type='chart' kind='line' requires x and at least one series."), ex.getMessage());
}
@Test void a38_applyTo_chartCardReservedBodyKey_rejected() {
var spec = PageSpec.create().card(CardSpec.of("chart", "trend").src("/s").body("kind", "line").body("title", "x"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg13 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg13, MODEL));
assertTrue(ex.getMessage().contains("reserved"), ex.getMessage());
}
@@ -320,7 +348,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a40_applyTo_chartCardWithTemplate_rejected() {
var spec = PageSpec.create().card(ChartDef.line("trend").src("/s").x("day").series("placed", "Placed").toCardSpec().template("tpl"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg14 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg14, MODEL));
assertTrue(ex.getMessage().contains("<@card id='trend'> type='chart' takes a JSON5 body (plus src= for remote data); template= is not allowed."), ex.getMessage());
}
@@ -346,38 +375,45 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a41c_applyTo_terminalCard_bareRefused() {
var spec = PageSpec.create().card(CardSpec.of("terminal", "out").body("terminal", Map.of("bytesUrl", "/t")));
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().card(CardSpec.of("terminal", "out").bare(true)));
+ var base = CardSpec.of("terminal", "out");
+ var ex = assertThrows(IllegalArgumentException.class, () -> base.bare(true));
assertTrue(ex.getMessage().contains("a terminal card does not support bare"), ex.getMessage());
assertDoesNotThrow(() -> spec.applyTo(new PageCapture(), MODEL));
}
@Test void a42_applyTo_jobLogCard_crossOriginEndpoint_rejected() {
+ var arg15 = new PageCapture();
var spec = PageSpec.create().card(CardSpec.of("job-log", "rebuild").body("submit", Map.of("endpoint", "//evil.test/x")));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg15, MODEL));
assertTrue(ex.getMessage().contains("type='job-log' submit.endpoint must be a same-origin path; got '//evil.test/x'."), ex.getMessage());
}
@Test void a43_applyTo_jobLogCardWithTemplate_rejected() {
var spec = PageSpec.create().card(CardSpec.of("job-log", "rebuild").body("submit", Map.of("endpoint", "/a")).template("tpl"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg16 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg16, MODEL));
assertTrue(ex.getMessage().contains("<@card id='rebuild'> type='job-log' takes its options as the body; template= is not allowed."), ex.getMessage());
}
@Test void a44_applyTo_jobLogCardWithSrc_rejected() {
var spec = PageSpec.create().card(CardSpec.of("job-log", "rebuild").src("/a").body("submit", Map.of("endpoint", "/a")));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg17 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg17, MODEL));
assertTrue(ex.getMessage().contains("<@card id='rebuild'> type='job-log' takes its options as the body; src= is not allowed."), ex.getMessage());
}
@Test void a45_applyTo_unsafeCardSrc_rejectedForNonLiftedType() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").src("\\\\evil.test/x"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg18 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg18, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> type='my-widget' src must be a same-origin path"), ex::getMessage);
}
@Test void a46_addCard_unsafeSrc_rejected() {
+ var target20 = new PageCapture();
+ var arg19 = CardSpec.html("h").src("//evil.test/x");
var ex = assertThrows(freemarker.template.TemplateModelException.class,
- () -> new PageCapture().addCard(CardSpec.html("h").src("//evil.test/x"), null));
+ () -> target20.addCard(arg19, null));
assertTrue(ex.getMessage().contains("<@card id='h'> type='html' src must be a same-origin path"), ex::getMessage);
assertDoesNotThrow(() -> new PageCapture().addCard(CardSpec.html("h").src("/ok/{id}"), null));
}
@@ -410,21 +446,25 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a50_htmlSrc_unsafeSrc_refusedAtApplyTo() {
for (var src : new String[]{"//evil.test/x", "https://evil.test/x", "javascript:alert(1)", "/a/../b", "\\\\evil.test/x"}) {
var spec = PageSpec.create().htmlSrc("h", "H", src);
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL), src);
+ var arg20 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg20, MODEL), src);
assertTrue(ex.getMessage().contains("<@card id='h'> type='html' src must be a same-origin path"), ex::getMessage);
}
}
@Test void a50b_htmlSrc_sanitizeWithUnsafeSrc_srcRefusalWins() {
+ var arg21 = new PageCapture();
var spec = PageSpec.create().htmlSrc("h", "H", "//evil.test/x", true);
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg21, MODEL));
assertTrue(ex.getMessage().contains("src must be a same-origin path"), ex::getMessage);
}
@Test void a51_htmlSrc_blankSrc_rejected() {
- var nul = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().htmlSrc("h", "H", null));
+ var target16 = PageSpec.create();
+ var nul = assertThrows(IllegalArgumentException.class, () -> target16.htmlSrc("h", "H", null));
assertEquals("PageSpec.htmlSrc id 'h' requires a non-blank src.", nul.getMessage());
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().htmlSrc("h", "H", " "));
+ var target17 = PageSpec.create();
+ assertThrows(IllegalArgumentException.class, () -> target17.htmlSrc("h", "H", " "));
}
@Test void a52_htmlSrc_sanitize_matchesTemplateTwin() throws Exception {
@@ -448,10 +488,12 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a55_sanitize_onNonHtmlOrSrcless_refusedWithTemplateMessage() {
var notHtml = PageSpec.create().card(CardSpec.of("my-widget", "t").src("/rest/data").sanitize(true));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> notHtml.applyTo(new PageCapture(), MODEL));
+ var arg22 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> notHtml.applyTo(arg22, MODEL));
assertTrue(ex.getMessage().contains("<@card id='t'> sanitize= applies only to an html card with src=."), ex::getMessage);
var noSrc = CardSpec.html("h").template("tpl").sanitize(true);
- var ex2 = assertThrows(freemarker.template.TemplateModelException.class, () -> new PageCapture().addCard(noSrc, null));
+ var target21 = new PageCapture();
+ var ex2 = assertThrows(freemarker.template.TemplateModelException.class, () -> target21.addCard(noSrc, null));
assertTrue(ex2.getMessage().contains("<@card id='h'> sanitize= applies only to an html card with src=."), ex2::getMessage);
}
@@ -467,13 +509,15 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a57_applyTo_invalidCustomCard_refusedByItsHandler() {
var spec = PageSpec.create().card(CardSpec.of("meter", "load").body("max", 4));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), CUSTOM));
+ var arg23 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg23, CUSTOM));
assertTrue(ex.getMessage().contains("<@card id='load'> type='meter' requires a numeric 'value'."), ex::getMessage);
}
@Test void a58_applyTo_customCardWithoutBody_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("meter", "load"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), CUSTOM));
+ var arg24 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg24, CUSTOM));
assertTrue(ex.getMessage().contains("<@card id='load'> type='meter' requires a JSON5 object body; got ''."), ex::getMessage);
}
@@ -491,13 +535,15 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a60_applyTo_unregisteredType_reservedBodyKey_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").body("template", "t"));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg25 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg25, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> body key 'template' is reserved; set it as an attribute."), ex::getMessage);
}
@Test void a61_applyTo_customCardWithBodyAndSrc_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").src("/rest/w").body("k", 1));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg26 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg26, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> type='my-widget' takes at most one of a body, template= or src=."), ex::getMessage);
}
@@ -516,7 +562,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a64_applyTo_customCardMarkup_isTheHandlersBody() {
var spec = PageSpec.create().card(CardSpec.of("meter", "load"), "<b>x</b>");
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), CUSTOM));
+ var arg27 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg27, CUSTOM));
assertTrue(ex.getMessage().contains("<@card id='load'> type='meter' requires a JSON5 object body; got '<b>x</b>'."), ex::getMessage);
}
@@ -531,7 +578,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a66_applyTo_customCardWithBodyAndMarkup_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").body("k", 1), "<b>x</b>");
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg28 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg28, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> type='my-widget' takes at most one of a body, template= or src=."), ex::getMessage);
}
@@ -544,7 +592,8 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a68_applyTo_customCardWithBodyAndTemplate_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").template("t").body("k", 1));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg29 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg29, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> type='my-widget' takes at most one of a body, template= or src=."), ex::getMessage);
}
@@ -568,13 +617,15 @@ class PageSpec_Cards_Test extends TestBase {
@Test void a71_applyTo_customCardJsonMarkupBusKeys_withSpecWiring_refusedWithTheTemplateMessage() {
var spec = PageSpec.create().card(CardSpec.of("my-widget", "w").subscribes(org.apache.juneau.rest.server.console.Subscription.to("ops.jobs").as("refresh")),
"{k: 1, subscribes: [ { topic: 'ssc.focus', as: 'refresh' } ]}");
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg30 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg30, MODEL));
assertTrue(ex.getMessage().contains("<@card id='w'> body key 'subscribes' is reserved; set it as an attribute."), ex::getMessage);
}
@Test void a72_applyTo_sanitizeOnCustomCard_refusedBeforeItsHandler() {
var spec = PageSpec.create().card(CardSpec.of("meter", "load").body("max", 4).sanitize(true));
- var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(new PageCapture(), CUSTOM));
+ var arg31 = new PageCapture();
+ var ex = assertThrows(freemarker.template.TemplateModelException.class, () -> spec.applyTo(arg31, CUSTOM));
assertTrue(ex.getMessage().contains("<@card id='load'> sanitize= applies only to an html card with src=."), ex::getMessage);
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Dashboard_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Dashboard_Test.java
index 7c630d7b9e..931d435a9d 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Dashboard_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Dashboard_Test.java
@@ -59,18 +59,22 @@ class PageSpec_Dashboard_Test extends TestBase {
@Test void a03_secondDashboard_isE77() {
var spec = PageSpec.create().html("notes", "<p>n</p>").dashboard(dash());
+ var arg = DashboardSpec.create("other");
assertEquals("E-77: dashboard 'other': a page has at most one dashboard",
- assertThrows(IllegalArgumentException.class, () -> spec.dashboard(DashboardSpec.create("other"))).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> spec.dashboard(arg)).getMessage());
}
@Test void a04_byIdPanel_mustPrecedeDashboard() {
+ var target = PageSpec.create();
+ var arg2 = dash();
assertEquals("E-77: dashboard 'orders': panel 'notes' names no card on this page",
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().dashboard(dash())).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target.dashboard(arg2)).getMessage());
}
@Test void a05_null_rejected() {
+ var target2 = PageSpec.create();
assertEquals("PageSpec.dashboard requires a dashboard.",
- assertThrows(IllegalArgumentException.class, () -> PageSpec.create().dashboard(null)).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target2.dashboard(null)).getMessage());
}
@Test void a06_earlyWiring_seesDashboard() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Data_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Data_Test.java
index f6d76c8a26..cb4b12fe37 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Data_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Data_Test.java
@@ -57,15 +57,19 @@ class PageSpec_Data_Test extends TestBase {
@Test void a03_duplicateId_isE76() {
var spec = PageSpec.create().data(DataSourceDef.create("orders").url("/a"));
- var e = assertThrows(IllegalArgumentException.class, () -> spec.data(DataSourceDef.create("orders").url("/b")));
+ var arg = DataSourceDef.create("orders").url("/b");
+ var e = assertThrows(IllegalArgumentException.class, () -> spec.data(arg));
assertEquals("E-76: data source 'orders': duplicate id", e.getMessage());
- e = assertThrows(IllegalArgumentException.class, () -> spec.data(Derived.from("x").as("orders")));
+ var arg2 = Derived.from("x").as("orders");
+ e = assertThrows(IllegalArgumentException.class, () -> spec.data(arg2));
assertEquals("E-76: data source 'orders': duplicate id", e.getMessage());
}
@Test void a04_badDeclaration_failsAtTheCallSite() {
- var e = assertThrows(IllegalArgumentException.class, () -> PageSpec.create()
- .data(DataSourceDef.create("orders")));
+ var target = PageSpec.create()
+ ;
+ var arg3 = DataSourceDef.create("orders");
+ var e = assertThrows(IllegalArgumentException.class, () -> target.data(arg3));
assertEquals("E-76: data source 'orders': url is required", e.getMessage());
}
@@ -79,7 +83,8 @@ class PageSpec_Data_Test extends TestBase {
@Test void a05_earlyWiring_runsWithDataSources() {
// A declared source is its data: topic's one publisher; without it the read is E-71, not E-41 (R-E1).
var reg = CardTypeRegistry.standard();
- var e = assertThrows(IllegalArgumentException.class, () -> withConsumer(false).checkWiringEarly(reg, null));
+ var target2 = withConsumer(false);
+ var e = assertThrows(IllegalArgumentException.class, () -> target2.checkWiringEarly(reg, null));
assertEquals("topic 'data:orders' needs exactly one source publisher; found 0", e.getMessage());
assertDoesNotThrow(() -> withConsumer(true).checkWiringEarly(reg, null));
assertDoesNotThrow(() -> page().checkWiringEarly(reg, null));
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Merge_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Merge_Test.java
index a746fca033..4cf05714b6 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Merge_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Merge_Test.java
@@ -19,8 +19,6 @@ package org.apache.juneau.rest.server.view.freemarker.console;
import static org.apache.juneau.rest.server.console.test.PageContractAssert.*;
import static org.junit.jupiter.api.Assertions.*;
-import java.util.*;
-
import org.apache.juneau.*;
import org.apache.juneau.commons.inject.*;
import org.apache.juneau.rest.mock.classic.*;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Parity_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Parity_Test.java
index cf83eafaca..8b3046ff55 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Parity_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Parity_Test.java
@@ -162,7 +162,7 @@ class PageSpec_Parity_Test extends TestBase {
@Test void case13_navUnderDepth3() throws Exception { assertParity("13-navunder-depth3", a -> a.hasActiveNav("fleet", "instances", "i-1", "logs")); }
@Test void case14_theme() throws Exception { assertParity("14-theme", a -> a.hasTheme("light-red")); }
@Test void case15_customCardType() throws Exception { assertParity("15-custom-card-type", a -> a.hasCard("slo-trend", "kpi")); }
- @Test void case16_csrfBodyAttrs() throws Exception { { assertParity("16-csrf-body-attrs", a -> {}); var html = get("/spec/16-csrf-body-attrs"); assertTrue(html.contains("data-app-flag") && html.contains("tok-123"), html); }; }
+ @Test void case16_csrfBodyAttrs() throws Exception { assertParity("16-csrf-body-attrs", a -> {}); var html = get("/spec/16-csrf-body-attrs"); assertTrue(html.contains("data-app-flag") && html.contains("tok-123"), html); }
@Test void case17_badgeVsDirective() throws Exception { assertParity("17-badge-vs-directive", a -> assertNotNull(a.contract().getMap("header").get("badges"), "header.badges")); }
@Test void case18_factsDeepMerge() throws Exception { assertParity("18-facts-deep-merge", a -> assertNotNull(a.contract().get("facts"), "facts")); }
@Test void case20_themeInherit() throws Exception { assertParity("20-theme-inherit", a -> assertEquals("open", a.contract().getMap("theme").get("name"))); }
@@ -213,8 +213,10 @@ class PageSpec_Parity_Test extends TestBase {
"quickStats", Map.of("id", "store", "items", List.of(
Map.of("id", "orders", "type", "segmented", "label", "Orders", "segments", List.of(
Map.of("label", "Placed", "count", 3), Map.of("label", "Approved", "count", 5, "tone", "accent"))))));
+ var target = new DatatablesCardType();
+ var arg = org.apache.juneau.rest.server.console.CardSource.create("datatables", "t").bodyMap(body).build();
var ex = assertThrows(IllegalArgumentException.class,
- () -> new DatatablesCardType().toFragment(org.apache.juneau.rest.server.console.CardSource.create("datatables", "t").bodyMap(body).build()));
+ () -> target.toFragment(arg));
assertEquals(msg, ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Test.java
index 62d7bd3063..2249bfbb22 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_Test.java
@@ -58,22 +58,26 @@ class PageSpec_Test extends TestBase {
}
@Test void a05_tab_blank_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().tab(""));
+ var target = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target.tab(""));
assertEquals(TAB_MSG.formatted(""), ex.getMessage());
}
@Test void a06_tab_null_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().tab(null));
+ var target2 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target2.tab(null));
assertEquals(TAB_MSG.formatted("null"), ex.getMessage());
}
@Test void a07_tab_emptySegment_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().tab("home//core"));
+ var target3 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target3.tab("home//core"));
assertEquals(TAB_MSG.formatted("home//core"), ex.getMessage());
}
@Test void a08_tab_trailingSlash_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().tab("home/"));
+ var target4 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target4.tab("home/"));
assertEquals(TAB_MSG.formatted("home/"), ex.getMessage());
}
@@ -90,7 +94,8 @@ class PageSpec_Test extends TestBase {
}
@Test void a11_theme_unknown_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().theme("teal"));
+ var target5 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target5.theme("teal"));
assertEquals("Unknown stock theme name: 'teal'. Built-in themes: open, light-red, light-brown, red, gray.", ex.getMessage());
}
@@ -107,29 +112,34 @@ class PageSpec_Test extends TestBase {
}
@Test void a14_header_title_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().header(h -> h.title("Nope")));
+ var target6 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target6.header(h -> h.title("Nope")));
assertEquals(HEADER_MSG.formatted("title"), ex.getMessage());
}
@Test void a15_header_logo_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().header(h -> h.logo("/img/logo.svg", "/", "Logo")));
+ var target7 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target7.header(h -> h.logo("/img/logo.svg", "/", "Logo")));
assertEquals(HEADER_MSG.formatted("logo"), ex.getMessage());
}
@Test void a16_header_chrome_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().header(h -> h.chrome(true)));
+ var target8 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target8.header(h -> h.chrome(true)));
assertEquals(HEADER_MSG.formatted("chrome"), ex.getMessage());
}
@Test void a17_header_link_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().header(h -> h.link("Docs", "/docs")));
+ var target9 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target9.header(h -> h.link("Docs", "/docs")));
assertEquals(HEADER_MSG.formatted("link"), ex.getMessage());
}
@Test void a18_addCard_duplicateId_rejected() {
var spec = PageSpec.create();
spec.addCard(CardSpec.html("intro"));
- var ex = assertThrows(IllegalArgumentException.class, () -> spec.addCard(CardSpec.html("intro")));
+ var arg = CardSpec.html("intro");
+ var ex = assertThrows(IllegalArgumentException.class, () -> spec.addCard(arg));
assertEquals("PageSpec card id 'intro' is already declared.", ex.getMessage());
}
@@ -165,13 +175,15 @@ class PageSpec_Test extends TestBase {
}
@Test void a22_attr_reservedKey_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().attr(PageSpec.ATTR, "x"));
+ var target10 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target10.attr(PageSpec.ATTR, "x"));
assertEquals("PageSpec.attr key 'jcPageSpec' is reserved for the spec itself.", ex.getMessage());
}
@Test void a23_header_userMenuUnknownKey_rejected() {
+ var target11 = PageSpec.create();
var ex = assertThrows(IllegalArgumentException.class,
- () -> PageSpec.create().header(h -> h.userMenu(Map.of("label", "Jane", "href", "/p"))));
+ () -> target11.header(h -> h.userMenu(Map.of("label", "Jane", "href", "/p"))));
assertEquals("PageSpec.header userMenu key 'href' is not allowed; allowed: label, initials, avatar, items.", ex.getMessage());
}
@@ -188,8 +200,9 @@ class PageSpec_Test extends TestBase {
}
@Test void a25_navUnder_blankPath_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().navUnder("", n -> {}));
- assertTrue(ex.getMessage().contains("navUnder"), () -> ex.getMessage());
+ var target12 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target12.navUnder("", n -> {}));
+ assertTrue(ex.getMessage().contains("navUnder"), ex::getMessage);
}
@Test void a26_navUnder_reusedSpec_eachCaptureGetsItsOwnAddition() throws Exception {
@@ -206,7 +219,8 @@ class PageSpec_Test extends TestBase {
}
@Test void a27_scheme_unknown_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().scheme("dim"));
+ var target13 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target13.scheme("dim"));
assertEquals("Unknown scheme 'dim'. Schemes: auto, light, dark.", ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_View_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_View_Test.java
index eb10f111fb..7d22d78466 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_View_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PageSpec_View_Test.java
@@ -134,13 +134,15 @@ class PageSpec_View_Test extends TestBase {
@Test void a01_view_noMixinBean_rejectedWithFoundNone() throws Exception {
var req = capture(NoMixinHost.class, NoMixinHost.CAPTURED);
- var ex = assertThrows(IllegalStateException.class, () -> PageSpec.create().view(req));
+ var target = PageSpec.create();
+ var ex = assertThrows(IllegalStateException.class, () -> target.view(req));
assertEquals("PageSpec.view needs a ConsoleFreemarkerMixin bean; found 'none'.", ex.getMessage());
}
@Test void a02_view_plainFreemarkerMixinBean_rejected() throws Exception {
var req = capture(PlainMixinHost.class, PlainMixinHost.CAPTURED);
- var ex = assertThrows(IllegalStateException.class, () -> PageSpec.create().view(req));
+ var target2 = PageSpec.create();
+ var ex = assertThrows(IllegalStateException.class, () -> target2.view(req));
assertEquals("PageSpec.view needs a ConsoleFreemarkerMixin bean; found 'FreemarkerMixin'.", ex.getMessage());
}
@@ -230,7 +232,8 @@ class PageSpec_View_Test extends TestBase {
}
@Test void a12_view_nullRequest_rejected() {
- var ex = assertThrows(IllegalArgumentException.class, () -> PageSpec.create().view(null));
+ var target3 = PageSpec.create();
+ var ex = assertThrows(IllegalArgumentException.class, () -> target3.view(null));
assertEquals("PageSpec.view requires a non-null request.", ex.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec_Test.java
index 3da43d9b83..8d199fc111 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/PersistSpec_Test.java
@@ -49,24 +49,32 @@ class PersistSpec_Test extends TestBase {
"1app|namespace '1app' does not match ^[a-z][a-z0-9.-]{0,63}$",
})
void a03_badNamespace(String ns, String detail) {
+ var target = PersistSpec.page(ns).topics(Topics.filter("r"));
assertEquals("E-77: dashboard 'd': " + detail,
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page(ns).topics(Topics.filter("r")).check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target.check("d")).getMessage());
}
@Test void a04_errors() {
+ var target2 = PersistSpec.page("a").version(0).topics(Topics.filter("r"));
assertEquals("E-77: dashboard 'd': persist version 0 must be at least 1",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").version(0).topics(Topics.filter("r")).check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target2.check("d")).getMessage());
+ var target3 = PersistSpec.page("a");
assertEquals("E-77: dashboard 'd': persist needs at least one topic",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target3.check("d")).getMessage());
+ var target4 = PersistSpec.page("a").topics(Topics.selection("t"));
assertEquals("E-77: dashboard 'd': persist topic 'selection:t' is not a filter:, zoom: or legend: state topic",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").topics(Topics.selection("t")).check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target4.check("d")).getMessage());
+ var target5 = PersistSpec.page("a").topics("app.x");
assertEquals("E-77: dashboard 'd': persist topic 'app.x' is not a filter:, zoom: or legend: state topic",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").topics("app.x").check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target5.check("d")).getMessage());
+ var target6 = PersistSpec.page("a").topics(Topics.filter("r"), Topics.filter("r"));
assertEquals("E-77: dashboard 'd': persist lists topic 'filter:r' twice",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").topics(Topics.filter("r"), Topics.filter("r")).check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target6.check("d")).getMessage());
+ var target7 = PersistSpec.page("a").topics(Topics.filter("r")).decoder("goto");
assertEquals("E-77: dashboard 'd': decoder name 'goto' is not a dotted extension name",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").topics(Topics.filter("r")).decoder("goto").check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target7.check("d")).getMessage());
+ var target8 = PersistSpec.page("a").topics(Topics.filter("r")).decoder("app.go").decoder("app.go");
assertEquals("E-77: dashboard 'd': decoder 'app.go' is listed twice",
- assertThrows(IllegalArgumentException.class, () -> PersistSpec.page("a").topics(Topics.filter("r")).decoder("app.go").decoder("app.go").check("d")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> target8.check("d")).getMessage());
}
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/SameOriginPath_Corpus_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/SameOriginPath_Corpus_Test.java
index e92872e831..525596bbad 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/SameOriginPath_Corpus_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/SameOriginPath_Corpus_Test.java
@@ -146,7 +146,8 @@ class SameOriginPath_Corpus_Test extends TestBase {
if (r.accepted())
assertFalse(threw, () -> e.getKey() + " card src '" + r.name() + "' must pass the page-build check");
else {
- var ex = assertThrows(IllegalArgumentException.class, () -> registry.toCard(e.getValue().apply(r.input())));
+ var arg = e.getValue().apply(r.input());
+ var ex = assertThrows(IllegalArgumentException.class, () -> registry.toCard(arg));
assertTrue(ex.getMessage().contains("'" + e.getValue().apply(r.input()).id() + "'"), () -> "names the card id: " + ex.getMessage());
assertTrue(ex.getMessage().contains("src"), ex::getMessage);
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Section_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Section_Test.java
index db0414469c..e7e8319b0f 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Section_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/Section_Test.java
@@ -140,7 +140,8 @@ class Section_Test extends TestBase {
@Test void a13_nullInputs() {
assertEquals("E-77: dashboard 'd': range section 'r' preset 'null' is not Nd, Nh or ytd",
e77(() -> RangeSection.quick("7d", null).publishes(Topics.filter("r")).check("d")));
- assertThrows(NullPointerException.class, () -> Rail.left().sections((Section)null));
+ var target = Rail.left();
+ assertThrows(NullPointerException.class, () -> target.sections((Section)null));
assertThrows(NullPointerException.class, () -> CardSection.of((CardSpec)null));
assertThrows(NullPointerException.class, () -> CardSection.of((ChartDef)null));
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType_Test.java
index 2bfe795497..033195d5ff 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCardType_Test.java
@@ -30,7 +30,9 @@ class TerminalCardType_Test extends TestBase {
var b = CardSource.create("terminal", "build");
if (body != null)
b.body(body);
- return assertThrows(IllegalArgumentException.class, () -> new TerminalCardType().toFragment(b.build()));
+ var target = new TerminalCardType();
+ var arg = b.build();
+ return assertThrows(IllegalArgumentException.class, () -> target.toFragment(arg));
}
@Test void a01_minimal() {
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCard_Parity_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCard_Parity_Test.java
index 29381aedf5..50d8e4ce6e 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCard_Parity_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TerminalCard_Parity_Test.java
@@ -78,14 +78,16 @@ class TerminalCard_Parity_Test extends TestBase {
envelope.put("contractVersion", "1");
envelope.putAll(body);
var source = CardSource.create("terminal", "build").body(Json5.of(envelope)).build();
- return assertThrows(IllegalArgumentException.class, () -> new TerminalCardType().toFragment(source)).getMessage();
+ var target = new TerminalCardType();
+ return assertThrows(IllegalArgumentException.class, () -> target.toFragment(source)).getMessage();
}
private static String builderMessage(Map<String,Object> body) {
var card = CardSpec.of("terminal", "build");
body.forEach(card::body);
var spec = PageSpec.create().card(card);
- return assertThrows(TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL)).getMessage();
+ var arg = new PageCapture();
+ return assertThrows(TemplateModelException.class, () -> spec.applyTo(arg, MODEL)).getMessage();
}
@ParameterizedTest(name = "{0}")
@@ -114,7 +116,8 @@ class TerminalCard_Parity_Test extends TestBase {
if (template != null)
card.template(template);
var spec = PageSpec.create().card(card);
- var ex = assertThrows(TemplateModelException.class, () -> spec.applyTo(new PageCapture(), MODEL));
+ var arg2 = new PageCapture();
+ var ex = assertThrows(TemplateModelException.class, () -> spec.applyTo(arg2, MODEL));
var body = C1Fixtures.renderError(fixture);
assertTrue(body.contains(ex.getMessage()), () -> "expected '" + ex.getMessage() + "' in:\n" + body);
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry_Test.java
index da4a75dded..f46ace387b 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/ToolkitPackRegistry_Test.java
@@ -93,7 +93,7 @@ class ToolkitPackRegistry_Test extends TestBase {
"juneau-ribbon.js", "juneau-views.js", "juneau-config.js", "juneau-regions.js",
"juneau-run-view.js", "juneau-helpers.js");
// The bus is the very first runtime JS entry.
- assertTrue(r.runtimeJs().get(0).toString().contains("juneau-bus.js"), () -> r.runtimeJs().toString());
+ assertTrue(r.runtimeJs().get(0).contains("juneau-bus.js"), () -> r.runtimeJs().toString());
assertEmpty(r.vendorCss());
assertEmpty(r.vendorJs());
}
@@ -118,7 +118,9 @@ class ToolkitPackRegistry_Test extends TestBase {
@Test void a05_unknownRequested_namesSource() throws Exception {
var reg = new ToolkitPackRegistry();
var req = dummyRequest();
- var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(List.of("nope"), req, List.of(), ""));
+ var arg = List.of("nope");
+ List<String> noPageUrls = List.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(arg, req, noPageUrls, ""));
assertString("Unknown toolkit pack 'nope' (requested).", e.getMessage());
}
@@ -185,8 +187,9 @@ class ToolkitPackRegistry_Test extends TestBase {
}
@Test void a13_checkWebJars_absentEcharts_isE70() {
- var e = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("charts"),
- a -> { throw new IllegalStateException("needs org.webjars.npm:echarts on the classpath (no META-INF/maven/org.webjars.npm/echarts/pom.properties)."); }));
+ var target = new ToolkitPackRegistry();
+ var arg2 = List.of("charts");
+ var e = assertThrows(IllegalStateException.class, () -> target.checkWebJars(arg2, a -> { throw new IllegalStateException("needs org.webjars.npm:echarts on the classpath (no META-INF/maven/org.webjars.npm/echarts/pom.properties)."); }));
assertContains("E-70: chart cards need the ECharts WebJar org.webjars.npm:echarts, which is not on the classpath; add it to the application's pom (version property 'webjars-echarts.version')", e.getMessage());
}
@@ -205,35 +208,42 @@ class ToolkitPackRegistry_Test extends TestBase {
.resolver((req, path) -> { throw new IllegalStateException("needs WebJar file 'echarts/6.1.0/dist/echarts.min.js' (org.webjars.npm:echarts:6.1.0), which is not on the classpath."); })
.js(ToolkitPackRegistry.ECHARTS_JS_ASSET).build());
var req = dummyRequest();
- var e = assertThrows(IllegalStateException.class, () -> reg.resolve(List.of("charts"), req, List.of(), "t.ftlh"));
+ var arg3 = List.of("charts");
+ List<String> noPageUrls2 = List.of();
+ var e = assertThrows(IllegalStateException.class, () -> reg.resolve(arg3, req, noPageUrls2, "t.ftlh"));
assertContains("E-70: chart cards need the ECharts WebJar org.webjars.npm:echarts, which is not on the classpath; add it to the application's pom (version property 'webjars-echarts.version')", e.getMessage());
}
@Test void a17_e70_appendsCauseMessage_soJarAbsentAndFileMissingDiffer() {
- var absent = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("charts"),
- a -> { throw new IllegalStateException("needs org.webjars.npm:echarts on the classpath (no META-INF/maven/org.webjars.npm/echarts/pom.properties)."); }));
- var missingFile = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("charts"),
- a -> { throw new IllegalStateException("needs WebJar file 'echarts/6.1.0/dist/echarts.min.js' (org.webjars.npm:echarts:6.1.0), which is not on the classpath."); }));
+ var target2 = new ToolkitPackRegistry();
+ var arg4 = List.of("charts");
+ var absent = assertThrows(IllegalStateException.class, () -> target2.checkWebJars(arg4, a -> { throw new IllegalStateException("needs org.webjars.npm:echarts on the classpath (no META-INF/maven/org.webjars.npm/echarts/pom.properties)."); }));
+ var target3 = new ToolkitPackRegistry();
+ var arg5 = List.of("charts");
+ var missingFile = assertThrows(IllegalStateException.class, () -> target3.checkWebJars(arg5, a -> { throw new IllegalStateException("needs WebJar file 'echarts/6.1.0/dist/echarts.min.js' (org.webjars.npm:echarts:6.1.0), which is not on the classpath."); }));
assertContains("[needs org.webjars.npm:echarts on the classpath (no META-INF/maven/org.webjars.npm/echarts/pom.properties).]", absent.getMessage());
assertContains("[needs WebJar file 'echarts/6.1.0/dist/echarts.min.js' (org.webjars.npm:echarts:6.1.0), which is not on the classpath.]", missingFile.getMessage());
- assertFalse(absent.getMessage().equals(missingFile.getMessage()));
+ assertNotEquals(absent.getMessage(), missingFile.getMessage());
}
@Test void a19_e70Pack_appendsCauseMessage() {
- var e = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("echarts-gl"),
- a -> { if (a.contains(":echarts-gl:")) throw new IllegalStateException("needs org.webjars.npm:echarts-gl on the classpath (no pom)."); return a; }));
+ var target4 = new ToolkitPackRegistry();
+ var arg6 = List.of("echarts-gl");
+ var e = assertThrows(IllegalStateException.class, () -> target4.checkWebJars(arg6, a -> { if (a.contains(":echarts-gl:")) throw new IllegalStateException("needs org.webjars.npm:echarts-gl on the classpath (no pom)."); return a; }));
assertTrue(e.getMessage().endsWith(" [needs org.webjars.npm:echarts-gl on the classpath (no pom).]"), e.getMessage());
}
@Test void a20_e70_nullCauseMessage_hasNoSuffix() {
- var e = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("charts"),
- a -> { throw new IllegalStateException((String)null); }));
+ var target5 = new ToolkitPackRegistry();
+ var arg7 = List.of("charts");
+ var e = assertThrows(IllegalStateException.class, () -> target5.checkWebJars(arg7, a -> { throw new IllegalStateException((String)null); }));
assertEquals("E-70: " + ToolkitPackRegistry.E70, e.getMessage());
}
@Test void a18_e70Pack_echartsGl_namesVersionProperty() {
- var e = assertThrows(IllegalStateException.class, () -> new ToolkitPackRegistry().checkWebJars(List.of("echarts-gl"),
- a -> { if (a.contains(":echarts-gl:")) throw new IllegalStateException("x"); return a; }));
+ var target6 = new ToolkitPackRegistry();
+ var arg8 = List.of("echarts-gl");
+ var e = assertThrows(IllegalStateException.class, () -> target6.checkWebJars(arg8, a -> { if (a.contains(":echarts-gl:")) throw new IllegalStateException("x"); return a; }));
assertContains("E-70: toolkit pack 'echarts-gl' needs the WebJar org.webjars.npm:echarts-gl, which is not on the classpath; add it to the application's pom (version property 'webjars-echarts-gl.version')", e.getMessage());
}
@@ -283,7 +293,9 @@ class ToolkitPackRegistry_Test extends TestBase {
var reg = new ToolkitPackRegistry();
reg.register(pack("x", VENDOR, "/x.js", "ghost"));
var req = dummyRequest();
- var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(List.of("x"), req, List.of(), ""));
+ var arg9 = List.of("x");
+ List<String> noPageUrls3 = List.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(arg9, req, noPageUrls3, ""));
assertString("Unknown toolkit pack 'ghost' (dependsOn of pack 'x').", e.getMessage());
}
@@ -300,7 +312,9 @@ class ToolkitPackRegistry_Test extends TestBase {
reg.register(pack("a", VENDOR, "/a.js", "b"));
reg.register(pack("b", VENDOR, "/b.js", "a"));
var req = dummyRequest();
- var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(List.of("b"), req, List.of(), ""));
+ var arg10 = List.of("b");
+ List<String> noPageUrls4 = List.of();
+ var e = assertThrows(IllegalArgumentException.class, () -> reg.resolve(arg10, req, noPageUrls4, ""));
assertString("Toolkit pack cycle: b → a → b.", e.getMessage());
}
@@ -349,7 +363,8 @@ class ToolkitPackRegistry_Test extends TestBase {
@Test void b14_requireKnown_namesSource() {
var reg = new ToolkitPackRegistry();
reg.requireKnown(List.of(ToolkitPackRegistry.PACK_VIEWS), "<@page toolkit=>");
- var e = assertThrows(IllegalArgumentException.class, () -> reg.requireKnown(List.of("views", "nope"), "<@page toolkit=>"));
+ var arg11 = List.of("views", "nope");
+ var e = assertThrows(IllegalArgumentException.class, () -> reg.requireKnown(arg11, "<@page toolkit=>"));
assertString("Unknown toolkit pack 'nope' (<@page toolkit=>).", e.getMessage());
}
@@ -357,7 +372,9 @@ class ToolkitPackRegistry_Test extends TestBase {
var reg = new ToolkitPackRegistry();
reg.register(ToolkitPack.create("p").kind(VENDOR).js("x").resolver((req, path) -> { throw new IllegalStateException("needs org.example:p on the classpath."); }).build());
var req = dummyRequest();
- var e = assertThrows(IllegalStateException.class, () -> reg.resolve(List.of("p"), req, List.of(), ""));
+ var arg12 = List.of("p");
+ List<String> noPageUrls5 = List.of();
+ var e = assertThrows(IllegalStateException.class, () -> reg.resolve(arg12, req, noPageUrls5, ""));
assertString("Pack 'p' needs org.example:p on the classpath.", e.getMessage());
}
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirective_Test.java b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirective_Test.java
index 08c3658e63..5ac6d662fd 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirective_Test.java
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/console/TopicDirective_Test.java
@@ -25,7 +25,6 @@ import org.apache.juneau.commons.inject.*;
import org.apache.juneau.marshall.marshaller.*;
import org.apache.juneau.rest.mock.classic.*;
import org.apache.juneau.rest.server.*;
-import org.apache.juneau.rest.server.console.*;
import org.apache.juneau.rest.server.console.test.*;
import org.apache.juneau.rest.server.servlet.*;
import org.apache.juneau.rest.server.view.*;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/adopter-static/js/probe.js b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/adopter-static/js/probe.js
index f10b867425..690634d7c0 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/adopter-static/js/probe.js
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/adopter-static/js/probe.js
@@ -14,4 +14,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-var probe = 1;
+const probe = 1;
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/foundry.txt b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/foundry.txt
index 4eb71eb775..f79f8bbbfa 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/foundry.txt
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/foundry.txt
@@ -1,3 +1,3 @@
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-dark.css?v=*">
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-light-brown.css?v=*">
-<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #dccaa6 0%, #e8dcc4 22%, #f2ebdc 55%, #faf6ee 100%);--jc-header-icon-color:#747474;--jc-accent:#a9772f;--jc-accent-wash:rgba(169,119,47,0.1);--jc-link:#754d16;--jc-text:#2e2415;--jc-text-soft:#2e2415cc;--jc-text-muted:#7a6a4f;--jc-border:#d8cbb0;--jc-border-2:#977f4e;--jc-card-bg:#ffffff;--jc-chrome-bg:#efe6d4;--jc-white:#ffffff;--jc-btn-primary:#8a6d3b;--jc-btn-primary-hover:# [...]
+<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #dccaa6 0%, #e8dcc4 22%, #f2ebdc 55%, #faf6ee 100%);--jc-header-icon-color:#747474;--jc-accent:#a9772f;--jc-accent-wash:rgba(169,119,47,0.1);--jc-link:#754d16;--jc-text:#2e2415;--jc-text-soft:#2e2415cc;--jc-text-muted:#7a6a4f;--jc-border:#d8cbb0;--jc-border-2:#977f4e;--jc-card-bg:#ffffff;--jc-chrome-bg:#efe6d4;--jc-white:#ffffff;--jc-btn-primary:#8a6d3b;--jc-btn-primary-hover:# [...]
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/jrm.txt b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/jrm.txt
index 68f0545b91..88f4fe71b5 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/jrm.txt
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/jrm.txt
@@ -1,3 +1,3 @@
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-dark.css?v=*">
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-light-red.css?v=*">
-<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #e8cfd3 0%, #f0dfe3 22%, #f6eef0 55%, #faf7f8 100%);--jc-header-icon-color:#747474;--jc-accent:#B42348;--jc-accent-wash:rgba(180,35,72,0.1);--jc-link:#8B1538;--jc-text:#2a181c;--jc-text-soft:#2a181ccc;--jc-text-muted:#6e585c;--jc-border:#e4d4d7;--jc-border-2:#a37c85;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3ecee;--jc-white:#ffffff;--jc-btn-primary:#6B1D2A;--jc-btn-primary-hover:#5 [...]
+<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #e8cfd3 0%, #f0dfe3 22%, #f6eef0 55%, #faf7f8 100%);--jc-header-icon-color:#747474;--jc-accent:#B42348;--jc-accent-wash:rgba(180,35,72,0.1);--jc-link:#8B1538;--jc-text:#2a181c;--jc-text-soft:#2a181ccc;--jc-text-muted:#6e585c;--jc-border:#e4d4d7;--jc-border-2:#a37c85;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3ecee;--jc-white:#ffffff;--jc-btn-primary:#6B1D2A;--jc-btn-primary-hover:#5 [...]
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/leaf-alias.txt b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/leaf-alias.txt
index 916025f8ca..ee6e1ee6b4 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/leaf-alias.txt
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/leaf-alias.txt
@@ -1,3 +1,3 @@
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-dark.css?v=*">
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-open.css?v=*">
-<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #b0c4df 0%, #c7d5e8 22%, #e4eaf2 55%, #f5f6f9 100%);--jc-header-icon-color:#747474;--jc-accent:#1589EE;--jc-accent-wash:rgba(21,137,238,0.1);--jc-link:#015194;--jc-text:#080707;--jc-text-soft:#080707cc;--jc-text-muted:#706e6b;--jc-border:#dddbda;--jc-border-2:#888c90;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3f2f2;--jc-white:#ffffff;--jc-btn-primary:#1a5297;--jc-btn-primary-hover:# [...]
+<style>html:root{--jc-font:'Inter', 'Source Sans 3', system-ui, sans-serif;--jc-page-bg:linear-gradient(180deg, #b0c4df 0%, #c7d5e8 22%, #e4eaf2 55%, #f5f6f9 100%);--jc-header-icon-color:#747474;--jc-accent:#1589EE;--jc-accent-wash:rgba(21,137,238,0.1);--jc-link:#015194;--jc-text:#080707;--jc-text-soft:#080707cc;--jc-text-muted:#706e6b;--jc-border:#dddbda;--jc-border-2:#888c90;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3f2f2;--jc-white:#ffffff;--jc-btn-primary:#1a5297;--jc-btn-primary-hover:# [...]
diff --git a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/ssc.txt b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/ssc.txt
index 026d073e3a..2c159d5a8f 100644
--- a/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/ssc.txt
+++ b/juneau-rest/juneau-rest-server-console-ui-freemarker/src/test/resources/golden/theme-override/ssc.txt
@@ -1,3 +1,3 @@
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-dark.css?v=*">
<link rel="stylesheet" href="/juneau-console/themes/juneau-theme-open.css?v=*">
-<style>html:root{--jc-font:'Inter', Arial, sans-serif;--jc-page-bg:linear-gradient(180deg, #f3f3f3 0%, #f3f3f3 100%);--jc-header-icon-color:#747474;--jc-accent:#1a6fb0;--jc-accent-wash:rgba(26,111,176,0.08);--jc-link:#3071c2;--jc-text:#181818;--jc-text-soft:#2e2e2e;--jc-text-muted:#747474;--jc-border:#e5e5e5;--jc-border-2:#ced4da;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3f3f3;--jc-white:#ffffff;--jc-btn-primary:#3071c2;--jc-btn-primary-hover:#005fb2;--jc-danger:#ba0517;--jc-success:#2e844a; [...]
+<style>html:root{--jc-font:'Inter', Arial, sans-serif;--jc-page-bg:linear-gradient(180deg, #f3f3f3 0%, #f3f3f3 100%);--jc-header-icon-color:#747474;--jc-accent:#1a6fb0;--jc-accent-wash:rgba(26,111,176,0.08);--jc-link:#3071c2;--jc-text:#181818;--jc-text-soft:#2e2e2e;--jc-text-muted:#747474;--jc-border:#e5e5e5;--jc-border-2:#ced4da;--jc-card-bg:#ffffff;--jc-chrome-bg:#f3f3f3;--jc-white:#ffffff;--jc-btn-primary:#3071c2;--jc-btn-primary-hover:#005fb2;--jc-danger:#ba0517;--jc-success:#2e844a; [...]
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BridgeDecl.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BridgeDecl.java
index 13943b9d2d..24f9ca009e 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BridgeDecl.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BridgeDecl.java
@@ -38,8 +38,11 @@ import org.apache.juneau.marshall.collections.*;
*/
public final class BridgeDecl {
- private final String id, transport, session;
- private final List<String> downstream = new ArrayList<>(), upstream = new ArrayList<>();
+ private final String id;
+ private final String transport;
+ private final String session;
+ private final List<String> downstream = new ArrayList<>();
+ private final List<String> upstream = new ArrayList<>();
private Integer maxAttempts;
private BridgeDecl(String id, String transport, String session) {
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BusWiringValidator.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BusWiringValidator.java
index 671b607e64..3bbfe2ffe6 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BusWiringValidator.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/BusWiringValidator.java
@@ -18,6 +18,7 @@ package org.apache.juneau.rest.server.console;
import java.util.*;
import java.util.regex.*;
+import java.util.stream.*;
import org.apache.juneau.marshall.collections.*;
@@ -46,6 +47,10 @@ import org.apache.juneau.marshall.collections.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class BusWiringValidator {
/**
@@ -98,6 +103,9 @@ public final class BusWiringValidator {
static final String E71 = "topic '%s' needs exactly one source publisher; found %s";
/** Names for $fn, decorators, sections, parsers, builders and transforms (rule R-E5); juneau-charts.js has the same literal. */
+ @SuppressWarnings({
+ "java:S5998" // Pattern text is pinned to the identical literal in the JS files; possessive quantifiers are not valid JS
+ })
public static final Pattern EXTENSION_NAME = Pattern.compile("^[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9-]*)*$");
/** ECharts event names a chart card's {@code on} may use. */
public static final Pattern EVENT_NAME = Pattern.compile("^[a-z][a-z0-9_]{0,31}$");
@@ -389,8 +397,7 @@ public final class BusWiringValidator {
// R-E2 (E-72), R-E5 (E-74) for one chart card.
void checkChart(Map<?,?> card) {
var id = str(card.get("id"));
- var pubs = new HashSet<String>();
- for (var p : maps(card.get("publishes"))) if (str(p.get("topic")) != null) pubs.add(str(p.get("topic")));
+ var pubs = maps(card.get("publishes")).stream().map(p -> str(p.get("topic"))).filter(Objects::nonNull).collect(Collectors.toSet());
if (card.get("on") instanceof Map<?,?> on)
for (var e : on.entrySet()) {
var ev = String.valueOf(e.getKey());
@@ -462,10 +469,8 @@ public final class BusWiringValidator {
// Only a chart card has a group; a data source or another card type is not a group member.
if (target == null || ! "chart".equals(str(target.get("type"))) || str(target.get("group")) != null)
return;
- var groups = new TreeSet<String>();
- for (var c : cards.values())
- if ("chart".equals(str(c.get("type"))) && str(c.get("group")) != null)
- groups.add(str(c.get("group")));
+ var groups = cards.values().stream().filter(c -> "chart".equals(str(c.get("type")))).map(c -> str(c.get("group")))
+ .filter(Objects::nonNull).collect(Collectors.toCollection(TreeSet::new));
add("E-73", E73, from, str(p.get("op")), groups.isEmpty() ? "<none>" : "<none> (page groups: " + String.join(", ", groups) + ")");
}
@@ -503,8 +508,7 @@ public final class BusWiringValidator {
if (name != null && name.startsWith("data:"))
declared.add(name);
}
- for (var id : sourceIds)
- declared.add("data:" + id);
+ sourceIds.stream().map(id -> "data:" + id).forEach(declared::add);
if (dashboard.get("status") instanceof List<?> status)
for (var o : status)
if (o instanceof String t && ! declared.contains(t))
@@ -840,6 +844,9 @@ public final class BusWiringValidator {
}
/** E-58: a terminal card with {@code input: true} must carry the whole input wiring (publish, subscribe, server topic, bridge). */
+ @SuppressWarnings({
+ "java:S135" // Guard clauses keep the card filtering readable
+ })
void checkTerminalInput() {
for (var c : cards.values()) {
if (! "terminal".equals(str(c.get("type"))))
@@ -903,6 +910,9 @@ public final class BusWiringValidator {
return o instanceof String s ? s : null;
}
+ @SuppressWarnings({
+ "java:S1452" // wildcard return reflects heterogeneous element types
+ })
static List<Map<?,?>> maps(Object o) {
var out = new ArrayList<Map<?,?>>();
if (o instanceof List<?> l)
@@ -922,10 +932,16 @@ public final class BusWiringValidator {
}
/** A datatables card's catalog (its {@code table}), or the card itself for every other shape. */
+ @SuppressWarnings({
+ "java:S1452" // wildcard return reflects heterogeneous element types
+ })
static Map<?,?> view(Map<?,?> card) {
return card.get("table") instanceof Map<?,?> t ? t : card;
}
+ @SuppressWarnings({
+ "java:S1452" // wildcard return reflects heterogeneous element types
+ })
static List<Map<?,?>> ribbon(Map<?,?> card) {
return maps(view(card).get("ribbon"));
}
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardSource.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardSource.java
index 97088d089f..839ad6f63e 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardSource.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardSource.java
@@ -97,8 +97,8 @@ public final class CardSource {
String template() { return template; }
/**
- * @return <jk>true</jk> when {@link #bodyMap(Map)} was used, or the raw body's first non-whitespace character
- * is {@code '{'}.
+ * @return <jk>true</jk> when {@link Builder#bodyMap(Map)} was used, or the raw body's first non-whitespace character
+ * is an opening curly brace.
*/
public boolean hasJsonBody() {
if (bodyMap != null)
@@ -109,7 +109,7 @@ public final class CardSource {
/**
* Parses the body as JSON5 (cached after the first call).
*
- * @return The parsed body, or the {@link #bodyMap(Map)} wrapped as a {@link JsonMap} when that was used.
+ * @return The parsed body, or the {@link Builder#bodyMap(Map)} wrapped as a {@link JsonMap} when that was used.
* @throws IllegalArgumentException E-25 if the body is not JSON5 shaped; E-24 if it is but fails to parse.
*/
public JsonMap json() {
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeHandler.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeHandler.java
index 311d7d8aef..219f7c94f3 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeHandler.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeHandler.java
@@ -93,6 +93,9 @@ public interface CardTypeHandler {
*
* @return The accepted role names, or {@code null} if unknown.
*/
+ @SuppressWarnings({
+ "java:S1168" // null means "unknown to Java" in the public API
+ })
default Set<String> acceptedRoles() { return null; }
/**
@@ -108,6 +111,9 @@ public interface CardTypeHandler {
*
* @return The handled op names, or {@code null} if unknown.
*/
+ @SuppressWarnings({
+ "java:S1168" // null means "unknown to Java" in the public API
+ })
default Set<String> acceptedOps() { return null; }
/**
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeRegistry.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeRegistry.java
index 804bd17aa3..43a6562e8e 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeRegistry.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/CardTypeRegistry.java
@@ -40,6 +40,9 @@ import org.apache.juneau.marshall.collections.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class CardTypeRegistry {
/**
@@ -127,7 +130,9 @@ public final class CardTypeRegistry {
if (src != null && ! SafePathTemplate.isSameOriginPath(src))
throw source.error("type='%s' src must be a same-origin path (no absolute URL, '//', scheme, '..', backslash, control character, or leading/trailing space); got '%s'.",
source.type(), src);
- Object visibleWhen = null, subscribes = null, publishes = null;
+ Object visibleWhen = null;
+ Object subscribes = null;
+ Object publishes = null;
if (source.hasJsonBody()) {
var body = source.json();
for (var key : body.keySet()) {
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/HtmlCardType.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/HtmlCardType.java
index b66a26b27e..b9bc1087a8 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/HtmlCardType.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/HtmlCardType.java
@@ -77,7 +77,8 @@ public final class HtmlCardType implements CardTypeHandler {
public JsonMap toFragment(CardSource source) {
if (source.hasJsonBody()) {
var body = source.body();
- var preview = body == null ? "" : (body.length() <= 40 ? body : body.substring(0, 40));
+ var shortBody = body != null && body.length() > 40 ? body.substring(0, 40) : body;
+ var preview = body == null ? "" : shortBody;
throw source.error("type='%s' requires a %s body; got '%s'.", "html", "markup", preview);
}
var frag = new JsonMap();
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Subscription.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Subscription.java
index 4f834374eb..3da04de672 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Subscription.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Subscription.java
@@ -48,7 +48,8 @@ public final class Subscription {
}
private final String topic;
- private String role, emptyText;
+ private String role;
+ private String emptyText;
private WhenEmpty whenEmpty;
private final Map<String,String> map = new LinkedHashMap<>();
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Theme.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Theme.java
index 9f58a64e18..69d6e8bf36 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Theme.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Theme.java
@@ -275,6 +275,11 @@ public final class Theme {
.token("--jc-page-nav-hairline", "2px") // line between page-nav sections row and children row
.token("--jc-page-nav-section-font-size", "13px") // Page Tabs (top row) type; independent of children
.token("--jc-page-nav-child-font-size", "12px") // page-nav children (second row) type; independent of sections
+ .token("--jc-nav-tab-padding-block", "8px") // Page Tab (and HTML-slot section) vertical padding; with line-height and the indicator border sets tab height
+ .token("--jc-nav-tab-padding-inline", "10px") // Page Tab horizontal padding
+ .token("--jc-nav-tab-line-height", "1.5") // Page Tab / Page Subtab line box (unitless multiple of the font size)
+ .token("--jc-page-nav-child-padding-block", "6px") // Page Subtab vertical padding; less than the tab's 8px so the strip stays subordinate
+ .token("--jc-page-nav-child-padding-inline", "10px") // Page Subtab horizontal padding
.token("--jc-card-shadow", "0 2px 2px rgba(0, 0, 0, 0.05)") // (c) content-card / title-card elevation; table-chrome clears it
.token("--jc-danger-wash", "#fdeceb") // (d) themeable .jc-btn-danger:hover fill (was a hardcoded hex)
.token("--jc-success-wash", "#eaf6ee") // (d) themeable .jc-btn-success:hover fill (was a hardcoded hex)
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Topics.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Topics.java
index f19ce21874..6c38739942 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Topics.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/Topics.java
@@ -31,6 +31,9 @@ import java.util.regex.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192" // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+})
public final class Topics {
/** The framework families, in the order {@code JuneauViews.bus.FRAMEWORK_FAMILIES} lists them (pinned by a test). */
@@ -49,7 +52,7 @@ public final class Topics {
/** Framework families a declaration may name (with a concrete key): {@code data} page-level, {@code zoom}/{@code legend} on a card. */
static final Set<String> DECLARABLE_FRAMEWORK = Set.of("data", "zoom", "legend");
static final Pattern ROLE = Pattern.compile("^[a-z][a-z0-9-]{0,31}$");
- static final Pattern MAP_PATH = Pattern.compile("^[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*$");
+ static final Pattern MAP_PATH = Pattern.compile("^[A-Za-z0-9_-]++(?:\\.[A-Za-z0-9_-]++)*+$");
/** Builder-time bridge session: same-origin path (no {@code //} or {@code /\}) or a {@code servlet:} / {@code context:} URI resolved at render. */
static final Pattern SESSION = Pattern.compile("^(/(?![/\\\\])|servlet:/|context:/)\\S*$");
/** The card and dashboard-section id grammar ({@code $defs/id} in the page schema). */
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesAggregator.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesAggregator.java
index 6c6cae60dc..be539e0bca 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesAggregator.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesAggregator.java
@@ -60,6 +60,10 @@ import org.apache.juneau.rest.server.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "java:S1192", // Repeated literals are contract wire keys; named constants would obscure the contract shape.
+ "java:S3776" // Validation and rendering chains many independent guards; splitting them adds no clarity.
+})
public final class SeriesAggregator {
/** The bucket units, finest first. */
@@ -137,6 +141,9 @@ public final class SeriesAggregator {
}
/** A rejected aggregate request: HTTP 400 with an E-75 message. */
+ @SuppressWarnings({
+ "java:S110" // The deep hierarchy comes from the REST framework's BadRequest exception chain, not from this class.
+ })
public static final class RequestException extends BadRequest {
private static final long serialVersionUID = 1L;
@@ -164,7 +171,8 @@ public final class SeriesAggregator {
/** A parsed aggregate request. */
public static final class Request {
- private final Instant start, end;
+ private final Instant start;
+ private final Instant end;
private final String bucket;
private final List<String> groupBy;
private final List<Measure> measures;
@@ -324,6 +332,9 @@ public final class SeriesAggregator {
* @param res The response.
* @throws IOException If the writer fails.
*/
+ @SuppressWarnings({
+ "resource" // The response writer is owned and closed by the container.
+ })
public void writeTo(RestResponse res) throws IOException {
res.setContentType("application/json;charset=utf-8");
res.setHeader("X-Content-Type-Options", "nosniff");
@@ -339,6 +350,9 @@ public final class SeriesAggregator {
* @return The result.
* @throws RequestException If the request names a field that is not allowed.
*/
+ @SuppressWarnings({
+ "java:S135" // Guard clauses keep the row loop readable
+ })
public Result aggregate(Request req, Stream<? extends SeriesSource.Row> rows) {
var fields = new ArrayList<String>(req.groupBy);
req.measures.stream().map(Measure::field).filter(Objects::nonNull).forEach(fields::add);
@@ -385,7 +399,7 @@ public final class SeriesAggregator {
return new Result(List.copyOf(dims), List.copyOf(types), columns, truncated);
}
- // acc[i] = {count, sum, min, max}
+ // Each acc[i] holds four slots in order: count, sum, min, max.
private static double[][] newAccumulators(int n) {
var a = new double[n][];
for (var i = 0; i < n; i++)
@@ -393,6 +407,9 @@ public final class SeriesAggregator {
return a;
}
+ @SuppressWarnings({
+ "java:S135" // Guard clauses keep the accumulation readable
+ })
private static void accumulate(List<Measure> measures, double[][] acc, SeriesSource.Row r) {
for (var i = 0; i < measures.size(); i++) {
var m = measures.get(i);
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesSource.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesSource.java
index eb94f0fd27..9e31d2eb7f 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesSource.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/data/SeriesSource.java
@@ -47,6 +47,9 @@ import org.apache.juneau.rest.server.*;
*
* @since 10.0.0
*/
+@SuppressWarnings({
+ "resource" // The output stream belongs to the response and is closed by the container, not by this streamer.
+})
public final class SeriesSource {
/** One row; {@link #get(String)} returns the value for a column, or null. */
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/test/AssetResolutionAssert.java b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/test/AssetResolutionAssert.java
index bff179fe3f..cf263d1e82 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/test/AssetResolutionAssert.java
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/java/org/apache/juneau/rest/server/console/test/AssetResolutionAssert.java
@@ -62,7 +62,7 @@ public final class AssetResolutionAssert {
var m = p.matcher(attrs);
if (! m.find())
return null;
- return m.group(1) != null ? m.group(1) : m.group(2);
+ return m.group(m.group(1) != null ? 1 : 2);
}
private static boolean isAssetLink(String attrs) {
@@ -118,6 +118,9 @@ public final class AssetResolutionAssert {
* @param statusOf Fetches a URL and returns its HTTP status code.
* @return One {@code "<status> <url>"} entry per failing asset, sorted; empty when every asset resolves.
*/
+ @SuppressWarnings({
+ "java:S4276" // A null status signals failure, so it cannot be a ToIntFunction
+ })
public static List<String> unresolved(String html, Function<String,Integer> statusOf) {
var bad = new TreeSet<String>();
for (var url : assetUrls(html)) {
@@ -135,6 +138,9 @@ public final class AssetResolutionAssert {
* @param statusOf Fetches a URL and returns its HTTP status code.
* @throws AssertionError If any linked asset does not resolve; the message lists each one.
*/
+ @SuppressWarnings({
+ "java:S4276" // A null status signals failure, so it cannot be a ToIntFunction
+ })
public static void assertAssetsResolve(String html, Function<String,Integer> statusOf) {
assertAssetsResolve(null, html, statusOf);
}
@@ -147,6 +153,9 @@ public final class AssetResolutionAssert {
* @param statusOf Fetches a URL and returns its HTTP status code.
* @throws AssertionError If any linked asset does not resolve; the message lists each one.
*/
+ @SuppressWarnings({
+ "java:S4276" // A null status signals failure, so it cannot be a ToIntFunction
+ })
public static void assertAssetsResolve(String page, String html, Function<String,Integer> statusOf) {
var bad = unresolved(html, statusOf);
if (! bad.isEmpty())
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/chrome.css b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/chrome.css
index 4c04cbf884..77e3bde93e 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/chrome.css
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/chrome.css
@@ -401,10 +401,12 @@ a:hover { text-decoration: underline; }
.jc-nav-tab {
display: flex;
align-items: center;
+ box-sizing: border-box;
font-size: 0.8125rem;
+ line-height: var(--jc-nav-tab-line-height);
font-weight: 400;
color: var(--jc-text-soft);
- padding: 9px 12px;
+ padding: var(--jc-nav-tab-padding-block) var(--jc-nav-tab-padding-inline);
margin-right: 0;
border-top: var(--jc-nav-indicator-width) solid transparent;
border-bottom: none;
@@ -422,6 +424,7 @@ a:hover { text-decoration: underline; }
border-top-color: var(--jc-page-nav-accent);
border-bottom: none;
color: var(--jc-text);
+ font-weight: 700;
}
/* ==========================================================================
@@ -525,10 +528,9 @@ a:hover { text-decoration: underline; }
flex: 0 0 auto;
display: inline-flex;
align-items: center;
- padding-top: 0.45em;
- padding-bottom: 0.45em;
- padding-left: var(--jc-space-3);
- padding-right: var(--jc-space-3);
+ box-sizing: border-box;
+ padding-left: var(--jc-nav-tab-padding-inline);
+ padding-right: var(--jc-nav-tab-padding-inline);
font-weight: 400;
text-decoration: none;
border: none;
@@ -538,6 +540,8 @@ a:hover { text-decoration: underline; }
}
.juneau-page-nav-section {
+ padding: var(--jc-nav-tab-padding-block) var(--jc-nav-tab-padding-inline);
+ line-height: var(--jc-nav-tab-line-height);
color: var(--jc-text-soft);
font-size: var(--jc-page-nav-section-font-size);
border-top-width: var(--jc-nav-indicator-width);
@@ -555,10 +559,12 @@ a:hover { text-decoration: underline; }
background-color: var(--jc-accent-wash);
border-top-color: var(--jc-page-nav-accent);
color: var(--jc-text);
- font-weight: 600;
+ font-weight: 700;
}
.juneau-page-nav-child {
+ padding: var(--jc-page-nav-child-padding-block) var(--jc-page-nav-child-padding-inline);
+ line-height: var(--jc-nav-tab-line-height);
color: var(--jc-text-soft);
font-size: var(--jc-page-nav-child-font-size);
}
@@ -572,6 +578,7 @@ a:hover { text-decoration: underline; }
.juneau-page-nav-child[aria-current="page"] {
color: var(--jc-text);
background-color: var(--jc-accent-wash);
+ font-weight: 700;
}
/* ==========================================================================
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-badges.js b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-badges.js
index 991820aa32..2fd8d32cd7 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-badges.js
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-badges.js
@@ -60,7 +60,7 @@
* (checked by ViewsJs_SameOriginPath_Test) and mirrors SafePathTemplate.isSameOriginPath. Callers handle the empty string.
*/
function hasUnsafeUrlChars(s) {
- return s.charCodeAt(0) <= 32 || s.charCodeAt(s.length - 1) <= 32 || /[\\\u0000-\u001f\u007f]/.test(s);
+ return s.codePointAt(0) <= 32 || s.codePointAt(s.length - 1) <= 32 || /[\\\u0000-\u001f\u007f]/.test(s);
}
// Exact parity with SafePathTemplate.isSameOriginPath (juneau-commons), the rule BadgeDef.validate applies to src and href.
diff --git a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-charts.js b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-charts.js
index 28e42ec836..7471a009cb 100644
--- a/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-charts.js
+++ b/juneau-rest/juneau-rest-server-console-ui/src/main/resources/org/apache/juneau/console/juneau-charts.js
@@ -52,7 +52,7 @@
const EVENT_NAME_RE = /^[a-z][a-z0-9_]{0,31}$/;
const REGISTRIES = ["fn", "decorator", "parser", "builder", "transform"];
// The theme tokens the ECharts theme is built from (ConsoleChromeMixin_Test c03 reads this list).
- const THEME_TOKENS = ["--jc-chart-1", "--jc-chart-2", "--jc-chart-3", "--jc-chart-4", "--jc-chart-5", "--jc-chart-6",
+ const THEME_TOKENS = ["--jc-chart-1", "--jc-chart-2", "--jc-chart-3", "--jc-chart-4", "--jc-chart-5", "--jc-chart-6", // NOSONAR javascript:S1481,javascript:S1854 - the list is read by the chrome token test
"--jc-chart-7", "--jc-chart-8", "--jc-chart-bg", "--jc-chart-text", "--jc-chart-axis", "--jc-chart-grid",
"--jc-chart-tooltip-bg", "--jc-chart-tooltip-text", "--jc-chart-mark", "--jc-chart-band", "--jc-chart-heat-low",
"--jc-chart-heat-high"];
@@ -99,17 +99,17 @@
function fmt(t) {
const args = Array.prototype.slice.call(arguments, 1);
let i = 0;
- return t.replace(/%s/g, () => String(args[i++]));
+ return t.replaceAll('%s', () => String(args[i++]));
}
function chartError(code) {
- const e = new Error(code + ": " + fmt.apply(null, [MSG[code]].concat(Array.prototype.slice.call(arguments, 1))));
+ const e = new Error(code + ": " + fmt(MSG[code], ...Array.prototype.slice.call(arguments, 1)));
e.code = code;
return e;
}
function log(e) {
- console.error("[juneau-charts] " + (e && e.message || e));
+ console.error("[juneau-charts] " + (e?.message || e));
}
function warn(msg) {
@@ -125,7 +125,7 @@
}
function msgOf(e) {
- return e && e.message || String(e);
+ return e?.message || String(e);
}
// ---- B. registries --------------------------------------------------------------------------------------------
@@ -156,7 +156,7 @@
return Object.freeze({
register: (name, impl) => register(kind, name, impl, false),
get: name => impls[kind].get(name) || null,
- names: () => Array.from(impls[kind].keys()).sort()
+ names: () => Array.from(impls[kind].keys()).sort(byCodeUnit)
});
}
@@ -198,13 +198,46 @@
}
function toNumber(v, type) {
- if (v == null || v === "") return NaN;
+ if (v == null || v === "") return Number.NaN;
if (type === "time" && typeof v === "string") return Date.parse(v);
const n = typeof v === "number" ? v : Number(v);
... 15293 lines suppressed ...