* WW-5653 docs: add Bootstrap 5.3.x sample-app migration design
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 docs: add Bootstrap 5 migration implementation plan
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 build: add Bootstrap 5, Bootstrap Icons, showcase jQuery webjars
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): serve Bootstrap 5 and jQuery via webjars
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): serve html5 demo Bootstrap CSS via webjar
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): migrate navbar and top-level pages to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): migrate leftover Bootstrap 2 icon and fixed-navbar classes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): migrate tag-demo pages to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): migrate validation-demo pages to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): migrate fileupload and conversion pages to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(showcase): migrate wait, token and empmanager pages to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): remove BS3 carets and well class
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): use ms-auto for right nav and add nav-link to Home
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(rest-showcase): serve Bootstrap 5 CSS via webjars
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 feat(rest-showcase): migrate JSP markup to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(rest-showcase): migrate legacy BS2/BS3 grid classes to Bootstrap 5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): drop obsolete css/js excludePattern so webjar JS is served
The old struts.action.excludePattern whitelisted the vendored /styles/*.css
and /js/*.js layout for container serving. After moving Bootstrap/jQuery to
webjars under /static/webjars/**, the '.*/js/.*\.js' entry matched the webjar
JS path (e.g. bootstrap.bundle.min.js) and excluded it from Struts' static
handler, so it fell through to the container and 404'd. Remaining webapp assets
(prettify.js, main.css) are served via default-servlet fall-through.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(samples): migrate remaining BS2/BS3 classes (tables, buttons, progress, forms, navbar)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 chore(showcase): comment out verbose debug loggers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): migrate Bootstrap 5 markup in ftl/vm/html templates
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 test(showcase): disable JS in FreeMarkerManagerTest for Bootstrap 5
HtmlUnit's JS engine cannot parse Bootstrap 5's ES6 (bootstrap.bundle.min.js
uses 'class'), and the decorator now serves it, so the default WebClient threw
on script error. The test only asserts server-rendered FreeMarker output, so
JavaScript is disabled (matching Html5TagExampleTest).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): replace dead Bootstrap 2 form and alert classes
Migrate new-person.ftl form off BS2 control-group/controls/form-actions to
Bootstrap 5 (mb-3, form-label, form-control), and replace the dead alert-error
class with alert-danger across the showcase pages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 test(showcase): make integration tests tolerate Bootstrap 5 under HtmlUnit
HtmlUnit 5.2.0 cannot parse Bootstrap 5's minified ES6 (bootstrap.bundle.min.js
uses 'class'), which broke the showcase HtmlUnit integration tests once the
decorator started serving the bundle.
- Add ParameterUtils.createWebClient() which disables throwExceptionOnScriptError,
and route all integration tests through it (they assert server-rendered output,
not Bootstrap's client-side behaviour).
- Load bootstrap.bundle.min.js with 'defer' so a page's own inline scripts (e.g.
the async chat demo) still execute before HtmlUnit hits the bundle's parse
error; defer is also the recommended real-browser loading strategy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 test(showcase): poll for async chat result instead of fixed sleep
AsyncTest relied on a fixed Thread.sleep(4000) for the server-push chat
round-trip, which is not enough on slower/newer JVMs (reproduced failing on
JDK 25). Poll the result element for up to ~30s via waitForBackgroundJavaScript
instead, making the test robust across JVMs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 test(showcase): drive AsyncTest via HTTP instead of HtmlUnit
The browser-driven chat test was flaky on JDK 25 in CI: HtmlUnit's handling of
the async server-push long-poll timed out (message never rendered), even with
polling. The test's purpose is to validate the Servlet 3 async endpoints, which
needs no browser or JavaScript. Rewrite it to POST /async/sendMessage and read
/async/receiveNewMessages directly over HTTP and assert the JSON, making it
deterministic and independent of Bootstrap/HtmlUnit JS parsing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): drop progressbar role from wait progress bar
Resolves a SonarCloud accessibility finding (S6819) introduced by the Bootstrap 5
migration. The BS5 progress component is styled on .progress/.progress-bar divs;
the role/aria attributes were newly added (the BS3 original had none), so removing
them clears the finding while keeping the Bootstrap 5 styling.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): correct BS5 alert wrapper and drop stray table tag
Address Copilot review on PR #1793:
- decorators/main.jsp: the dismissible wrapper was a second .alert with no
variant while the variant class (alert-danger, etc.) stayed on the inner
<ul>, producing a nested, uncoloured alert box. Move the alert* classes
onto the wrapper and strip them from the <ul> so the wrapper is the single
alert container.
- orders-edit.jsp: remove the stray, unclosed <table> start tag before
</s:form> (pre-existing invalid markup carried over during the migration).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): remove BS3 navbar-header wrapper and orphan dropdown-submenu
Clean up two leftover Bootstrap 3 artifacts in the showcase decorator navbar:
- Drop the `navbar-header` wrapper (no BS5 CSS behind it) and make the brand
and toggler direct children of the `.container-fluid` flex container
(justify-content: space-between), with the brand first per BS5 convention.
- Remove the empty, unclosed `<li class="dropdown-submenu">` orphan before the
first item in the Examples menu; BS5 has no dropdown-submenu feature.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): replace soft-deprecated navbar-light with data-bs-theme
navbar-light is soft-deprecated in Bootstrap 5.3. Switch the showcase navbar
to the current data-bs-theme="light" idiom; bg-light is retained for the
background.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(showcase): normalize page-header replacement to border-bottom utilities
A handful of showcase pages replaced the BS3 page-header with a bare <div>
while the rest used <div class="border-bottom pb-2 mb-3">. Normalize those 35
header wrappers to the same border-bottom pb-2 mb-3 utilities so all showcase
page headers render consistently.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5653 fix(rest-showcase): add mb-3 to page-header replacement
Align rest-showcase order page headers with the showcase standard by using
border-bottom pb-2 mb-3 (was border-bottom pb-2), so header spacing is
consistent across both sample apps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* WW-5537 Add InternalDestroyable and ContextAwareDestroyable interfaces
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 ContainerHolder: ThreadLocal with AtomicLong generation counter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 FinalizableReferenceQueue: volatile instance, join, classloader null
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 ScopeInterceptor.clearLocks: add synchronized block
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 CompoundRootAccessor, DefaultFileManager: implement InternalDestroyable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Add InternalDestroyable adapter classes for static cache cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Register InternalDestroyable beans in struts-beans.xml
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 JSON plugin: add JSONCacheDestroyable for BeanInfo cache cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Dispatcher.cleanup: refactor into focused methods with InternalDestroyable discovery
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Rewrite DispatcherCleanupTest for InternalDestroyable discovery
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Add log4j-web for proper Log4j2 lifecycle in Servlet container
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Dispatcher.destroyObjectFactory: add early return on null, use pattern matching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Fix @since annotations: 7.1.0 -> 7.2.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Add Container.destroy() to clear internal caches on undeploy
Container now exposes a destroy() method that clears factories, injectors,
constructors, and ThreadLocals. This releases Class<?> keys and JDK
DelegatingClassLoader instances that pin the webapp classloader.
DefaultConfiguration.destroy() calls container.destroy() and
reloadContainer() delegates to destroy() to avoid duplication.
Also fixes JSONCacheDestroyable referencing non-existent DefaultJSONWriter
(renamed to StrutsJSONWriter).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Fix Container.destroy(): don't clear factories, don't call from reloadContainer
factories must remain intact because existing code holds direct
references to the Container after destroyConfiguration() and expects
it to still resolve dependencies (e.g. during configuration reload).
reloadContainer() reverted to clearing packageContexts/loadedFileNames
directly — calling destroy() there nulled the container reference and
cleared state needed during the bootstrap transition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Restore destroy() call in reloadContainer()
The test failures were caused by factories.clear() in
Container.destroy(), not by calling destroy() from reloadContainer().
Now that factories.clear() is removed, destroy() is safe to call
here — it clears packageContexts, loadedFileNames, and the container's
reflection caches in one place.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* WW-5537 Fix Sonar issues: thread-safe FinalizableReferenceQueue, empty method comments
- Replace volatile field with AtomicReference in FinalizableReferenceQueue
for proper thread safety using getAndSet()
- Add comments to empty destroy() implementations in test mocks
- Replace deprecated new URL() with URI.toURL() in DispatcherCleanupTest
- Add comments to empty listener methods in DispatcherCleanupTest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add production deployment warnings to showcase and rest-showcase READMEs
- Convert README.txt to README.md with proper Markdown formatting
- Restrict ViewSourceAction config parameter to XML files within webapp path
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(proxy): WW-5514 add StrutsProxyService for proxy detection and resolution
Introduces a configurable ProxyService interface and StrutsProxyService
implementation for detecting and resolving Spring AOP/Hibernate proxies.
Key changes:
- Add ProxyService interface with isProxy, ultimateTargetClass, and
resolveTargetMember methods
- Add StrutsProxyService implementation using configurable caches
- Add ProxyCacheFactory and StrutsProxyCacheFactory for cache management
- Integrate ProxyService into ChainingInterceptor, ParametersInterceptor,
and SecurityMemberAccess
- Add integration test with Spring AOP proxied action chaining
- Add configuration constants for proxy cache type and size
The StrutsProxyService correctly handles:
- Spring CGLIB proxies (class-based)
- Spring JDK dynamic proxies (interface-based)
- Hibernate entity proxies
- Member resolution for allowlist checking
Fixes WW-5514
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(proxy): WW-5514 add ProxyService integration tests for Spring proxies
Add integration tests to SpringProxyUtilTest that verify the new
ProxyService works correctly with real Spring AOP proxies, alongside
the existing deprecated ProxyUtil tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(proxy): WW-5514 address PR review feedback for proxy caches
Remove targetClassCache from StrutsProxyService to avoid memory leak
(object-keyed cache reintroduced from PR #1578). Change default proxy
cache type to wtlfu to align with all other caches. Switch deprecated
ProxyUtil static caches to BASIC to remove hard Caffeine dependency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* WW-5444 Defines new html5 theme
* feat(themes): move html5 theme from showcase to core
- Move 42 FreeMarker templates to core/src/main/resources/template/html5/
- Remove duplicate templates from showcase
- Makes html5 theme available to all applications via struts2-core.jar
- Enables unit testing in core module
- Fix Html5Action import from XWork2 to Struts2 package
- Add Apache license header to Html5Action
Resolves WW-5444
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: add implementation plan for html5 theme migration
Add detailed implementation plan documenting the migration of html5 theme
from showcase to core, including step-by-step instructions, verification
procedures, and acceptance criteria.
Related to WW-5444
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(html5-theme): add comprehensive unit tests and fix template variables
- Add testGenericHtml5() methods to 13 UI tag test classes
- Create theme.properties with parent=simple configuration
- Migrate all 32 HTML5 templates from deprecated 'parameters' to 'attributes' variable
- Exclude DoubleSelect and UpDownSelect (not supported in HTML5 theme)
- All 26 HTML5 theme tests passing (100% success rate)
Components tested: Textfield, Textarea, Password, Checkbox, CheckboxList,
Radio, Select, File, Hidden, Label, ComboBox, Reset, Submit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: update CLAUDE.md and remove jakarta-migration-helper agent
- Update CLAUDE.md with current project guidelines
- Update test-runner agent documentation
- Remove deprecated jakarta-migration-helper agent
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Adds missing header
* test(html5-theme): complete unit test coverage for remaining 5 tag classes
Add HTML5 theme tests to ActionErrorTagTest, ActionMessageTagTest,
FieldErrorTagTest, AnchorTest, and FormTagTest. This completes Phase 1
of the HTML5 theme testing plan.
Changes:
- Add 24 new HTML5 theme unit tests across 5 test classes
- Create 17 expected output files for HTML5 theme validation
- Test coverage: action errors, action messages, field errors, anchors, and forms
- All tests verify HTML5 clean markup without table-based layouts
Coverage: 18 of 18 UI tag test classes now have HTML5 tests (100%)
Tests passing: 24/24 HTML5 tests successful
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(html5-theme): add integration tests for showcase application
- Create Html5TagExampleTest with 5 comprehensive integration tests
- Add fielderror tag demonstration to html5/index.jsp
- Validate HTML5 theme rendering, error display, and clean markup
- All tests passing (5/5) with HtmlUnit and Jetty integration
Tests validate:
- Page load and HTTP status (200)
- Action errors, messages, and field errors display
- Clean semantic markup (ul lists, no table layouts)
- Anchor tag rendering
- Namespace isolation under /html5
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(html5-theme): WW-5444 replace FreeMarker compress with Struts compress tag
- Create CompressModel.java to enable <@s.compress> in FreeMarker templates
- Register compress tag in StrutsModels.java for @s namespace access
- Migrate all 29 HTML5 theme templates from <#compress> to <@s.compress>
- Maintain identical compression behavior (uses same >\\s+< regex pattern)
- All 153 HTML5 theme unit tests pass without modification
This change leverages the new configurable Compress component (WW-5256)
which provides devMode awareness and security protections while maintaining
the same whitespace removal behavior as FreeMarker's built-in directive.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat(html5-theme): WW-5444 simplifies tags templates and extends example
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(fileupload): implement dynamic parameter evaluation for file upload validation
- Add WithLazyParams interface to ActionFileUploadInterceptor
- Enable runtime evaluation of ${...} expressions for validation rules
- Add comprehensive JavaDoc with static and dynamic examples
- Add 7 new unit tests for dynamic parameter scenarios
- Create DynamicFileUploadAction showcase with document/image modes
- All 23 tests pass successfully
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(fileupload): address Sonar quality issues in dynamic upload feature
- Mark uploadConfig field as transient for serialization compliance
- Add @Override annotation to input() method
- Add DOCTYPE html declarations to JSP files
- Add lang="en" attributes to html elements for accessibility
- Fix minor code formatting issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(fileupload): add integration tests for dynamic file upload
- Add DynamicFileUploadTest with 7 comprehensive test cases
- Test valid document and image uploads
- Test file type validation (documents reject images, images reject documents)
- Test size limit validation (5MB for documents, 2MB for images)
- Test switching between upload modes
- Add helper methods for creating test files of various sizes
- Follow existing FileUploadTest patterns using HtmlUnit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(fileupload): use Preparable to initialize upload config before interceptors
Read uploadType directly from request in prepareUpload() method to ensure
upload validation config is set before WithLazyParams interceptor evaluates
the OGNL expressions. This fixes dynamic file type validation not working.
Also fixes:
- Test file creation using correct File.createTempFile prefix pattern
- Default port changed to 8090 in test utils
- Increased struts.multipart.maxSize for testing
- maximumSize parameter changed to String to support OGNL expressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(fileupload): simplify maximumSize type from String to Long
- Change maximumSize field type from String to Long for type safety
- Remove NumberUtils dependency and parsing logic
- Remove unused isNonEmpty() method
- Modernize instanceof patterns using Java 16+ pattern matching
- Fix error message key for null content validation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs(research): add lazy multipart parsing research for WW-5585
Documents investigation into dynamic file upload limits at parsing time.
Conclusion: current approach with global hard limits + WithLazyParams
interceptor validation is sufficient.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* [maven-release-plugin] prepare release STRUTS_7_1_1
* [maven-release-plugin] rollback the release of STRUTS_7_1_1
* [maven-release-plugin] prepare release STRUTS_7_1_1
* [maven-release-plugin] prepare for next development iteration