diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c3464f762..11e27f287 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -52,12 +52,12 @@ jobs: java-version: 17 cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards-analysis.yaml b/.github/workflows/scorecards-analysis.yaml index d6992e44a..180cd9712 100644 --- a/.github/workflows/scorecards-analysis.yaml +++ b/.github/workflows/scorecards-analysis.yaml @@ -58,13 +58,13 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # 3.1.3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # 4.0.0 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b398f525a5587552e573b247ac661067fafa920b # 2.1.22 + uses: github/codeql-action/upload-sarif@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # 2.22.11 with: sarif_file: results.sarif diff --git a/apps/showcase/src/main/webapp/WEB-INF/decorators/main.jsp b/apps/showcase/src/main/webapp/WEB-INF/decorators/main.jsp index 34f732db3..9003e52ed 100644 --- a/apps/showcase/src/main/webapp/WEB-INF/decorators/main.jsp +++ b/apps/showcase/src/main/webapp/WEB-INF/decorators/main.jsp @@ -72,7 +72,7 @@ - + $(function () { var alerts = $('ul.alert').wrap(''); alerts.prepend('×'); diff --git a/apps/showcase/src/main/webapp/WEB-INF/validation/ajaxFormSubmit.jsp b/apps/showcase/src/main/webapp/WEB-INF/validation/ajaxFormSubmit.jsp index 3064aa251..cf8fddaeb 100644 --- a/apps/showcase/src/main/webapp/WEB-INF/validation/ajaxFormSubmit.jsp +++ b/apps/showcase/src/main/webapp/WEB-INF/validation/ajaxFormSubmit.jsp @@ -72,7 +72,7 @@ - + /******************************************************************** * JS just used on this page. * Usually this would be placed in a JS file diff --git a/assembly/src/main/resources/template.vm b/assembly/src/main/resources/template.vm index e254e59a0..07189c060 100644 --- a/assembly/src/main/resources/template.vm +++ b/assembly/src/main/resources/template.vm @@ -1,6 +1,6 @@ #set ($stylebase = "https://struts.apache.org/css") - @@ -43,12 +43,12 @@ under the License. #end - #end - + @s.script> ${debugHtml?no_esc} diff --git a/core/src/main/resources/org/apache/struts2/interceptor/debugging/console.ftl b/core/src/main/resources/org/apache/struts2/interceptor/debugging/console.ftl index 4aaccaa01..520a8add1 100644 --- a/core/src/main/resources/org/apache/struts2/interceptor/debugging/console.ftl +++ b/core/src/main/resources/org/apache/struts2/interceptor/debugging/console.ftl @@ -21,7 +21,7 @@ - <@s.script type="text/javascript"> + <@s.script> var baseUrl = "<@s.url value="/static" includeParams="none"/>"; window.open(baseUrl+"/webconsole.html", 'OGNL Console','width=500,height=450,status=no,toolbar=no,menubar=no'); @s.script> diff --git a/core/src/main/resources/struts-beans.xml b/core/src/main/resources/struts-beans.xml index 1238c9e05..754bccd07 100644 --- a/core/src/main/resources/struts-beans.xml +++ b/core/src/main/resources/struts-beans.xml @@ -174,11 +174,19 @@ - + + + + - diff --git a/core/src/main/resources/template/css_xhtml/form-validate.ftl b/core/src/main/resources/template/css_xhtml/form-validate.ftl index da7b24080..8d46b594d 100644 --- a/core/src/main/resources/template/css_xhtml/form-validate.ftl +++ b/core/src/main/resources/template/css_xhtml/form-validate.ftl @@ -19,7 +19,7 @@ */ --> <#if parameters.validate!false == true> - +<@s.script src="${base}${parameters.staticContentPath}/css_xhtml/validation.js"/> <#if parameters.onsubmit??> ${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")} <#else> diff --git a/core/src/main/resources/template/simple/combobox.ftl b/core/src/main/resources/template/simple/combobox.ftl index 1cef11754..733e33c5f 100644 --- a/core/src/main/resources/template/simple/combobox.ftl +++ b/core/src/main/resources/template/simple/combobox.ftl @@ -18,7 +18,7 @@ * under the License. */ --> -<@s.script type="text/javascript"> +<@s.script> function autoPopulate_${parameters.escapedId}(targetElement) { <#if parameters.headerKey?? && parameters.headerValue??> if (targetElement.options[targetElement.selectedIndex].value == '${parameters.headerKey?js_string}') { diff --git a/core/src/main/resources/template/simple/doubleselect.ftl b/core/src/main/resources/template/simple/doubleselect.ftl index 2a87e30f5..a0c5cf82d 100644 --- a/core/src/main/resources/template/simple/doubleselect.ftl +++ b/core/src/main/resources/template/simple/doubleselect.ftl @@ -114,7 +114,7 @@ #if> /><#rt/> #if> -<@s.script type="text/javascript"> +<@s.script> <#assign itemCount = startCount/> var ${parameters.escapedId}Group = new Array(${parameters.listSize?number?c} + ${startCount}); for (var i = 0; i < (${parameters.listSize?number?c} + ${startCount}); i++) { diff --git a/core/src/main/resources/template/simple/form-close-tooltips.ftl b/core/src/main/resources/template/simple/form-close-tooltips.ftl index 1a418b985..6007081c4 100644 --- a/core/src/main/resources/template/simple/form-close-tooltips.ftl +++ b/core/src/main/resources/template/simple/form-close-tooltips.ftl @@ -24,6 +24,6 @@ --><#t/> <#if (parameters.hasTooltip!false)><#t/> <#lt/> - <#lt/><@s.script type="text/javascript" src="${base}${parameters.staticContentPath}/domTT.js" /> + <#lt/><@s.script src="${base}${parameters.staticContentPath}/domTT.js" /> <#lt/><@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/domTT.css" /> #if><#t/> diff --git a/core/src/main/resources/template/simple/form-close.ftl b/core/src/main/resources/template/simple/form-close.ftl index ce2b91259..f8bb047d6 100644 --- a/core/src/main/resources/template/simple/form-close.ftl +++ b/core/src/main/resources/template/simple/form-close.ftl @@ -21,7 +21,7 @@ <#if (parameters.customOnsubmitEnabled??)> -<@s.script type="text/javascript"> +<@s.script> <#-- Enable auto-select of optiontransferselect tag's entries upon containing form's submission. diff --git a/core/src/main/resources/template/simple/head.ftl b/core/src/main/resources/template/simple/head.ftl index 82fe8db20..623ec70f2 100644 --- a/core/src/main/resources/template/simple/head.ftl +++ b/core/src/main/resources/template/simple/head.ftl @@ -18,4 +18,4 @@ * under the License. */ --> -<@s.script src="${base}${parameters.staticContentPath}/utils.js" type="text/javascript" /> +<@s.script src="${base}${parameters.staticContentPath}/utils.js" /> diff --git a/core/src/main/resources/template/simple/inputtransferselect.ftl b/core/src/main/resources/template/simple/inputtransferselect.ftl index 9b28a02ce..117390ea7 100644 --- a/core/src/main/resources/template/simple/inputtransferselect.ftl +++ b/core/src/main/resources/template/simple/inputtransferselect.ftl @@ -19,7 +19,7 @@ */ --> <#if !stack.findValue("#inputtransferselect_js_included")??><#t/> - <@s.script type="text/javascript" src="${base}${parameters.staticContentPath}/inputtransferselect.js"/> + <@s.script src="${base}${parameters.staticContentPath}/inputtransferselect.js"/> <#assign temporaryVariable = stack.setValue("#inputtransferselect_js_included", "true") /><#t/> #if><#t/> diff --git a/core/src/main/resources/template/simple/optiontransferselect.ftl b/core/src/main/resources/template/simple/optiontransferselect.ftl index adf770499..408196e0d 100644 --- a/core/src/main/resources/template/simple/optiontransferselect.ftl +++ b/core/src/main/resources/template/simple/optiontransferselect.ftl @@ -19,7 +19,7 @@ */ --> <#if !stack.findValue("#optiontransferselect_js_included")??><#t/> - <@s.script type="text/javascript" src="${base}${parameters.staticContentPath}/optiontransferselect.js" /> + <@s.script src="${base}${parameters.staticContentPath}/optiontransferselect.js" /> <#assign temporaryVariable = stack.setValue("#optiontransferselect_js_included", "true") /><#t/> #if><#t/> diff --git a/core/src/main/resources/template/simple/updownselect.ftl b/core/src/main/resources/template/simple/updownselect.ftl index 7491f9a08..a67194f63 100644 --- a/core/src/main/resources/template/simple/updownselect.ftl +++ b/core/src/main/resources/template/simple/updownselect.ftl @@ -19,7 +19,7 @@ */ --> <#if !stack.findValue("#optiontransferselect_js_included")??><#t/> - <@s.script type="text/javascript" src="${base}${parameters.staticContentPath}/optiontransferselect.js" /><#t/> + <@s.script src="${base}${parameters.staticContentPath}/optiontransferselect.js" /><#t/> <#assign temporaryVariable = stack.setValue("#optiontransferselect_js_included", "true") /><#t/> #if><#t/> diff --git a/core/src/main/resources/template/xhtml/form-close-validate.ftl b/core/src/main/resources/template/xhtml/form-close-validate.ftl index dfc338cbc..dce718e6c 100644 --- a/core/src/main/resources/template/xhtml/form-close-validate.ftl +++ b/core/src/main/resources/template/xhtml/form-close-validate.ftl @@ -32,7 +32,7 @@ Only the following validators are supported: END SNIPPET: supported-validators --> <#if ((parameters.validate!false == true) && (parameters.performValidation!false == true))> -<@s.script type="text/javascript"> +<@s.script> function validateForm_${parameters.escapedId}() { <#-- In case of multiselect fields return only the first value. diff --git a/core/src/main/resources/template/xhtml/form-close.ftl b/core/src/main/resources/template/xhtml/form-close.ftl index 300de7a04..1d17228b7 100644 --- a/core/src/main/resources/template/xhtml/form-close.ftl +++ b/core/src/main/resources/template/xhtml/form-close.ftl @@ -22,7 +22,7 @@ <#include "/${parameters.templateDir}/simple/form-close.ftl" /> <#include "/${parameters.templateDir}/${parameters.expandTheme}/form-close-validate.ftl" /> <#if parameters.focusElement??> -<@s.script type="text/javascript"> +<@s.script> StrutsUtils.addOnLoad(function() { var element = document.getElementById("${parameters.focusElement?js_string}"); if(element) { diff --git a/core/src/main/resources/template/xhtml/form-validate.ftl b/core/src/main/resources/template/xhtml/form-validate.ftl index 028c5d9ec..ffd811610 100644 --- a/core/src/main/resources/template/xhtml/form-validate.ftl +++ b/core/src/main/resources/template/xhtml/form-validate.ftl @@ -19,7 +19,7 @@ */ --> <#if parameters.validate!false == true> - <@s.script type="text/javascript" src="${base}${parameters.staticContentPath}/xhtml/validation.js" /> + <@s.script src="${base}${parameters.staticContentPath}/xhtml/validation.js" /> <#if parameters.onsubmit??> ${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")} <#else> diff --git a/core/src/site/confluence/ww-template-autoexport.html b/core/src/site/confluence/ww-template-autoexport.html index 0d0c24ff1..dc9424dc8 100644 --- a/core/src/site/confluence/ww-template-autoexport.html +++ b/core/src/site/confluence/ww-template-autoexport.html @@ -49,7 +49,7 @@ under the License. color: #666; } - + - + @@ -21,7 +21,7 @@ - + - + @@ -21,7 +21,7 @@ - - + - + @@ -21,7 +21,7 @@ - - + - + @@ -21,7 +21,7 @@ - - + @@ -20,9 +20,9 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt index f3c81d10e..ef160a5c2 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt @@ -1,7 +1,7 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt index 9c11a87b4..6260cc68c 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt @@ -1,7 +1,7 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt index f16886524..c94d40565 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt @@ -1,7 +1,7 @@ - - + + - + @@ -24,15 +24,15 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, 'Header Key', '');" /> - + Title Right - - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt index 359475c64..1939871cb 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt @@ -1,7 +1,7 @@ - + - + @@ -25,14 +25,14 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, 'Header Key', '');" /> Title Right - diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt index 46724ab70..1b0d645d5 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt @@ -1,7 +1,7 @@ - + - + @@ -24,15 +24,15 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, '');" /> Title Right - diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt index 39d5b1b79..6f0952327 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt @@ -1,7 +1,7 @@ - + - + @@ -25,15 +25,15 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, 'Header Key', '');" /> Title Right - @@ -45,7 +45,7 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt index fb0c97934..2cdccaefe 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt @@ -1,7 +1,7 @@ - - + + - + @@ -24,15 +24,15 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, 'Header Key', '');" /> Title Right - diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt index 68b99d066..56fdba726 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt @@ -1,7 +1,7 @@ - + - + @@ -25,15 +25,15 @@ + value="All Right" onclick="moveAllOptions(document.getElementById('id'), document.getElementById('doubleId'), false, 'Header Key', '');" /> Title Right - diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt index 270464f26..e5a039230 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt @@ -1,7 +1,7 @@ - + - + @@ -22,12 +22,12 @@ value="Left" onclick="moveSelectedOptions(document.getElementById('doubleId'), document.getElementById('id'), false, 'Double Header Key', '');alert('Moving Left');" /> - + Title Right - diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt index 4f6274914..69358f932 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt @@ -1,7 +1,7 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-1.txt index d34b31d2d..e80e91683 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-1.txt @@ -15,7 +15,7 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-2.txt index e04c68858..13b40700a 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-2.txt @@ -15,5 +15,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-3.txt index a70521455..5c891772d 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/tooltip-3.txt @@ -16,6 +16,6 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt index 3d3542779..eb86508da 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt index 74e0ab553..76489dda3 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt @@ -1,9 +1,9 @@ - + - + England America Australia @@ -12,9 +12,9 @@ - - - + + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt index 3f68bc62e..943766ef6 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt index f890aed35..fd2d70840 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt index 004b42ad9..3a1cf7e65 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt index 2e54fc103..c27eeb97d 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt index 37629caaa..168ed9c07 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt index c0fbd7558..47644f52d 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt index 75f15d775..551e39741 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt index 90e4e0b6c..d089a88be 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt @@ -1,5 +1,5 @@ - + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt index 5869c6783..26d4629bc 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt @@ -1,5 +1,5 @@ - + diff --git a/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java b/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java index 764e72945..460cab49e 100644 --- a/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java +++ b/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java @@ -24,14 +24,23 @@ import com.opensymphony.xwork2.FileManagerFactory; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationException; -import com.opensymphony.xwork2.config.entities.*; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig; +import com.opensymphony.xwork2.config.entities.InterceptorMapping; +import com.opensymphony.xwork2.config.entities.PackageConfig; +import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.AnnotationUtils; import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.WildcardHelper; import com.opensymphony.xwork2.util.classloader.ReloadingClassLoader; -import com.opensymphony.xwork2.util.finder.*; +import com.opensymphony.xwork2.util.finder.ClassFinder; +import com.opensymphony.xwork2.util.finder.ClassFinderFactory; +import com.opensymphony.xwork2.util.finder.ClassLoaderInterface; +import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate; +import com.opensymphony.xwork2.util.finder.Test; +import com.opensymphony.xwork2.util.finder.UrlSet; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -39,26 +48,50 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsException; -import org.apache.struts2.convention.annotation.*; +import org.apache.struts2.convention.annotation.Action; +import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.AllowedMethods; +import org.apache.struts2.convention.annotation.DefaultInterceptorRef; +import org.apache.struts2.convention.annotation.ExceptionMapping; +import org.apache.struts2.convention.annotation.ExceptionMappings; +import org.apache.struts2.convention.annotation.Namespace; +import org.apache.struts2.convention.annotation.Namespaces; +import org.apache.struts2.convention.annotation.ParentPackage; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** - * * This class implements the ActionConfigBuilder interface. - * */ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { private static final Logger LOG = LogManager.getLogger(PackageBasedActionConfigBuilder.class); + + private static final String DEFAULT_ACTION_SUFFIX = "Action"; + private static final String DEFAULT_METHOD = "execute"; + private static final boolean EXTRACT_BASE_INTERFACES = true; + /** + * Pattern to match the whole path with sub-path as on JDK9+ getClassLoader().getResources("") + * can return also a sub-path like "!/META-INF/versions/..." + */ + private static final String EXCLUDE_ALL_JARS_PATTERN = ".*?\\.jar(!/|/)?(.*)?"; + private static final String DEFAULT_SPLIT_PATTERN = "\\s*,\\s*"; + private final Configuration configuration; private final ActionNameBuilder actionNameBuilder; private final ResultMapBuilder resultMapBuilder; @@ -66,6 +99,9 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { private final ObjectFactory objectFactory; private final String defaultParentPackage; private final boolean redirectToSlash; + private final Set loadedFileUrls = new HashSet<>(); + private final boolean enableSmiInheritance; + private String[] actionPackages; private String[] excludePackages; private String[] packageLocators; @@ -73,20 +109,17 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { private String packageLocatorsBasePackage; private boolean disableActionScanning = false; private boolean disablePackageLocatorsScanning = false; - private Set actionSuffix = Collections.singleton("Action"); + private Set actionSuffix = Collections.singleton(DEFAULT_ACTION_SUFFIX); private boolean checkImplementsAction = true; private boolean mapAllMatches = false; - private Set loadedFileUrls = new HashSet<>(); + private boolean devMode; private ReloadingClassLoader reloadingClassLoader; private boolean reload; - private Set fileProtocols; + private Set fileProtocols = Collections.emptySet(); private boolean alwaysMapExecute; private boolean excludeParentClassLoader; private boolean slashesInActionNames; - private boolean enableSmiInheritance; - - private static final String DEFAULT_METHOD = "execute"; private boolean eagerLoading = false; private FileManager fileManager; @@ -95,16 +128,17 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * Constructs actions based on a list of packages. * - * @param configuration The XWork configuration that the new package configs and action configs - * are added to. - * @param container Xwork Container - * @param objectFactory The ObjectFactory used to create the actions and such. - * @param redirectToSlash A boolean parameter that controls whether or not this will create an - * action for indexes. If this is set to true, index actions are not created because - * the unknown handler will redirect from /foo to /foo/. The only action that is created - * is to the empty action in the namespace (e.g. the namespace /foo and the action ""). - * @param enableSmiInheritance A boolean parameter which determines if a newly created package config inherits the SMI value of its parent package config - * @param defaultParentPackage The default parent package for all the configuration. + * @param configuration The XWork configuration that the new package configs and action configs + * are added to. + * @param container Xwork Container + * @param objectFactory The ObjectFactory used to create the actions and such. + * @param redirectToSlash A boolean parameter that controls whether or not this will create an + * action for indexes. If this is set to true, index actions are not created because + * the unknown handler will redirect from /foo to /foo/. The only action that is created + * is to the empty action in the namespace (e.g. the namespace /foo and the action ""). + * @param enableSmiInheritance A boolean parameter, which determines if a newly created package config inherits + * the SMI value of its parent package config + * @param defaultParentPackage The default parent package for all the configuration. */ @Inject public PackageBasedActionConfigBuilder(Configuration configuration, Container container, ObjectFactory objectFactory, @@ -135,7 +169,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * @param reload Reload configuration when classes change. Defaults to "false" and should not be used - * in production. + * in production. */ @Inject(ConventionConstants.CONVENTION_CLASSES_RELOAD) public void setReload(String reload) { @@ -157,8 +191,8 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { } /** - * @param alwaysMapExecute If this constant is true, and there is an "execute" method(not annotated), a mapping will be added - * pointing to it, even if there are other mapping in the class + * @param alwaysMapExecute If this constant is true, and there is an "execute" method(not annotated), a mapping will be added + * pointing to it, even if there are other mapping in the class */ @Inject(ConventionConstants.CONVENTION_ACTION_ALWAYS_MAP_EXECUTE) public void setAlwaysMapExecute(String alwaysMapExecute) { @@ -167,6 +201,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * File URLs whose protocol are in these list will be processed as jars containing classes + * * @param fileProtocols Comma separated list of file protocols that will be considered as jar files and scanned */ @Inject(ConventionConstants.CONVENTION_ACTION_FILE_PROTOCOLS) @@ -190,7 +225,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { @Inject(value = ConventionConstants.CONVENTION_ACTION_INCLUDE_JARS, required = false) public void setIncludeJars(String includeJars) { if (StringUtils.isNotEmpty(includeJars)) { - this.includeJars = includeJars.split("\\s*[,]\\s*"); + this.includeJars = includeJars.split(DEFAULT_SPLIT_PATTERN); } } @@ -209,13 +244,13 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { @Inject(value = ConventionConstants.CONVENTION_ACTION_PACKAGES, required = false) public void setActionPackages(String actionPackages) { if (StringUtils.isNotBlank(actionPackages)) { - this.actionPackages = actionPackages.split("\\s*[,]\\s*"); + this.actionPackages = actionPackages.split(DEFAULT_SPLIT_PATTERN); } } /** * @param checkImplementsAction (Optional) Map classes that implement com.opensymphony.xwork2.Action - * as actions + * as actions */ @Inject(value = ConventionConstants.CONVENTION_ACTION_CHECK_IMPLEMENTS_ACTION, required = false) public void setCheckImplementsAction(String checkImplementsAction) { @@ -240,7 +275,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { @Inject(value = ConventionConstants.CONVENTION_EXCLUDE_PACKAGES, required = false) public void setExcludePackages(String excludePackages) { if (StringUtils.isNotBlank(excludePackages)) { - this.excludePackages = excludePackages.split("\\s*[,]\\s*"); + this.excludePackages = excludePackages.split(DEFAULT_SPLIT_PATTERN); } } @@ -249,7 +284,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { */ @Inject(value = ConventionConstants.CONVENTION_PACKAGE_LOCATORS, required = false) public void setPackageLocators(String packageLocators) { - this.packageLocators = packageLocators.split("\\s*[,]\\s*"); + this.packageLocators = packageLocators.split(DEFAULT_SPLIT_PATTERN); } /** @@ -273,7 +308,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * @param eagerLoading (Optional) If set, found action classes will be instantiated by the ObjectFactory to accelerate future use - * setting it up can clash with Spring managed beans + * setting it up can clash with Spring managed beans */ @Inject(value = ConventionConstants.CONVENTION_ACTION_EAGER_LOADING, required = false) public void setEagerLoading(String eagerLoading) { @@ -293,7 +328,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { protected void initReloadClassLoader() { //when the configuration is reloaded, a new classloader will be setup if (isReloadEnabled() && reloadingClassLoader == null) - reloadingClassLoader = new ReloadingClassLoader(getClassLoader()); + reloadingClassLoader = new ReloadingClassLoader(getClassLoader()); } protected ClassLoader getClassLoader() { @@ -324,17 +359,17 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { if (LOG.isTraceEnabled()) { LOG.trace("Loading action configurations"); if (actionPackages != null) { - LOG.trace("Actions being loaded from action packages: {}", actionPackages); + LOG.trace("Actions being loaded from action packages: {}", (Object[]) actionPackages); } if (packageLocators != null) { - LOG.trace("Actions being loaded using package locator's: {}", packageLocators); + LOG.trace("Actions being loaded using package locator's: {}", (Object[]) packageLocators); } if (excludePackages != null) { - LOG.trace("Excluding actions from packages: {}", excludePackages); + LOG.trace("Excluding actions from packages: {}", (Object[]) excludePackages); } } - Set classes = findActions(); + Set> classes = findActions(); buildConfiguration(classes); } } @@ -342,8 +377,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { protected ClassLoaderInterface getClassLoaderInterface() { if (isReloadEnabled()) { return new ClassLoaderInterfaceDelegate(this.reloadingClassLoader); - } - else { + } else { /* if there is a ClassLoaderInterface in the context, use it, otherwise default to the default ClassLoaderInterface (a wrapper around the current @@ -365,9 +399,8 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { return devMode && reload; } - @SuppressWarnings("unchecked") - protected Set findActions() { - Set classes = new HashSet<>(); + protected Set> findActions() { + Set> classes = new HashSet<>(); try { if (actionPackages != null || (packageLocators != null && !disablePackageLocatorsScanning)) { @@ -438,30 +471,26 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { } //try to find classes dirs inside war files - urlSet = urlSet.includeClassesUrl(classLoaderInterface, new UrlSet.FileProtocolNormalizer() { - public URL normalizeToFileProtocol(URL url) { - return fileManager.normalizeToFileProtocol(url); - } - }); - + urlSet = urlSet.includeClassesUrl(classLoaderInterface, url -> fileManager.normalizeToFileProtocol(url)); urlSet = urlSet.excludeJavaExtDirs() - .excludeJavaEndorsedDirs() - .excludeUserExtensionsDir(); + .excludeJavaEndorsedDirs() + .excludeUserExtensionsDir(); try { - urlSet = urlSet.excludeJavaHome(); + urlSet = urlSet.excludeJavaHome(); } catch (NullPointerException e) { - // This happens in GAE since the sandbox contains no java.home directory - LOG.warn("Could not exclude JAVA_HOME, is this a sandbox jvm?"); + // This happens in GAE since the sandbox contains no java.home directory + LOG.warn("Could not exclude JAVA_HOME, is this a sandbox jvm?"); } urlSet = urlSet.excludePaths(System.getProperty("sun.boot.class.path", "")); urlSet = urlSet.exclude(".*/JavaVM.framework/.*"); if (includeJars == null) { - urlSet = urlSet.exclude(".*?\\.jar(!/|/)?"); + LOG.debug("\"{}\" is not defined, excluding all JAR files!", ConventionConstants.CONVENTION_ACTION_INCLUDE_JARS); + urlSet = urlSet.exclude(EXCLUDE_ALL_JARS_PATTERN); } else { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("jar urls regexes were specified: {}", Arrays.asList(includeJars)); } List rawIncludedUrls = urlSet.getUrls(); @@ -509,7 +538,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { * * @param className the name of the class to test * @return true if the specified class should be included in the - * package-based action scan + * package-based action scan */ protected boolean includeClassNameInActionScan(String className) { String classPackageName = StringUtils.substringBeforeLast(className, "."); @@ -523,15 +552,15 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { * @return false if class package is on the {@link #excludePackages} list */ protected boolean checkExcludePackages(String classPackageName) { - if(excludePackages != null && excludePackages.length > 0) { + if (excludePackages != null && excludePackages.length > 0) { WildcardHelper wildcardHelper = new WildcardHelper(); //we really don't care about the results, just the boolean Map matchMap = new HashMap<>(); - for(String packageExclude : excludePackages) { + for (String packageExclude : excludePackages) { int[] packagePattern = wildcardHelper.compilePattern(packageExclude); - if(wildcardHelper.match(matchMap, classPackageName, packagePattern)) { + if (wildcardHelper.match(matchMap, classPackageName, packagePattern)) { return false; } } @@ -564,9 +593,9 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { * @return true if class package is on the {@link #packageLocators} list */ protected boolean checkPackageLocators(String classPackageName) { - if (packageLocators != null && !disablePackageLocatorsScanning && classPackageName.length() > 0 + if (packageLocators != null && !disablePackageLocatorsScanning && !classPackageName.isEmpty() && (packageLocatorsBasePackage == null || classPackageName - .startsWith(packageLocatorsBasePackage))) { + .startsWith(packageLocatorsBasePackage))) { for (String packageLocator : packageLocators) { String[] splitted = classPackageName.split("\\."); @@ -586,14 +615,10 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { * is to return the result of {@link #includeClassNameInActionScan(String)}. * * @return a {@link Test} object that returns true if the specified class - * name should be included in the package scan + * name should be included in the package scan */ protected Test getClassPackageTest() { - return new Test() { - public boolean test(String className) { - return includeClassNameInActionScan(className); - } - }; + return this::includeClassNameInActionScan; } /** @@ -604,7 +629,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { * super-classes of the specified class. * * @return a {@link Test} object that returns true if the specified class - * should be included in the package scan + * should be included in the package scan */ protected Test getActionClassTest() { return new Test() { @@ -638,8 +663,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { }; } - @SuppressWarnings("unchecked") - protected void buildConfiguration(Set classes) { + protected void buildConfiguration(Set> classes) { Map packageConfigs = new HashMap<>(); for (Class> actionClass : classes) { @@ -754,7 +778,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { private Set getAllowedMethods(Class> actionClass) { List annotations = AnnotationUtils.findAnnotations(actionClass, AllowedMethods.class); - if (annotations == null || annotations.isEmpty()) { + if (annotations.isEmpty()) { return Collections.emptySet(); } else { Set methods = new HashSet<>(); @@ -767,6 +791,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * Interfaces, enums, annotations, and abstract classes cannot be instantiated. + * * @param actionClass class to check * @return returns true if the class cannot be instantiated or should be ignored */ @@ -885,7 +910,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { } else { Action ann = method.getAnnotation(Action.class); if (ann != null) { - map.put(method.getName(), Arrays.asList(ann)); + map.put(method.getName(), Collections.singletonList(ann)); } } } @@ -894,7 +919,8 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { } /** - * Builds a list of actions from an @Actions annotation, and check that they are not all empty + * Builds a list of actions from an @Actions annotation, and check that they are not all empty + * * @param actionsAnnotation Actions annotation * @return a list of Actions */ @@ -926,12 +952,12 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { */ protected void createActionConfig(PackageConfig.Builder pkgCfg, Class> actionClass, String actionName, String actionMethod, Action annotation, Set allowedMethods) { - String className = actionClass.getName(); + String className = actionClass.getName(); if (annotation != null) { actionName = annotation.value().equals(Action.DEFAULT_VALUE) ? actionName : annotation.value(); actionName = StringUtils.contains(actionName, "/") && !slashesInActionNames ? StringUtils.substringAfterLast(actionName, "/") : actionName; - if(!Action.DEFAULT_VALUE.equals(annotation.className())){ - className = annotation.className(); + if (!Action.DEFAULT_VALUE.equals(annotation.className())) { + className = annotation.className(); } } @@ -988,8 +1014,10 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { //watch class file if (isReloadEnabled()) { URL classFile = actionClass.getResource(actionClass.getSimpleName() + ".class"); - fileManager.monitorFile(classFile); - loadedFileUrls.add(classFile.toString()); + if (classFile != null) { + fileManager.monitorFile(classFile); + loadedFileUrls.add(classFile.toString()); + } } } @@ -998,7 +1026,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { for (ExceptionMapping exceptionMapping : exceptions) { LOG.trace("Mapping exception [{}] to result [{}] for action [{}]", exceptionMapping.exception(), - exceptionMapping.result(), actionName); + exceptionMapping.result(), actionName); ExceptionMappingConfig.Builder builder = new ExceptionMappingConfig.Builder(null, exceptionMapping .exception(), exceptionMapping.result()); builder.addParams(StringTools.createParameterMap(exceptionMapping.params())); @@ -1009,8 +1037,8 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { } protected PackageConfig.Builder getPackageConfig(final Map packageConfigs, - String actionNamespace, final String actionPackage, final Class> actionClass, - Action action) { + String actionNamespace, final String actionPackage, final Class> actionClass, + Action action) { if (action != null && !action.value().equals(Action.DEFAULT_VALUE)) { LOG.trace("Using non-default action namespace from the Action annotation of [{}]", action.value()); String actionName = action.value(); @@ -1067,7 +1095,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder { /** * Determine all the index handling actions and results based on this logic: - * + * * 1. Loop over all the namespaces such as /foo and see if it has an action named index * 2. If an action doesn't exists in the parent namespace of the same name, create an action * in the parent namespace of the same name as the namespace that points to the index diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java index 4241f6ead..d18ca6bcf 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java @@ -19,6 +19,7 @@ package org.apache.struts2.views.velocity; import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.util.ValueStackProvider; import org.apache.velocity.VelocityContext; import java.util.ArrayList; @@ -26,7 +27,7 @@ import java.util.Arrays; import java.util.List; import java.util.function.Function; -public class StrutsVelocityContext extends VelocityContext { +public class StrutsVelocityContext extends VelocityContext implements ValueStackProvider { private final ValueStack stack; private final List chainedContexts; @@ -77,10 +78,10 @@ public class StrutsVelocityContext extends VelocityContext { } protected List> contextGetterList() { - return Arrays.asList(this::superGet, this::chainedContextGet, this::stackGet); + return Arrays.asList(this::superInternalGet, this::chainedContextGet, this::stackGet); } - protected Object superGet(String key) { + protected Object superInternalGet(String key) { return super.internalGet(key); } @@ -96,11 +97,16 @@ public class StrutsVelocityContext extends VelocityContext { return null; } for (VelocityContext chainedContext : chainedContexts) { - Object val = chainedContext.internalGet(key); + Object val = chainedContext.get(key); if (val != null) { return val; } } return null; } + + @Override + public ValueStack getValueStack() { + return stack; + } } diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java index e05fbe450..3e5996930 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java @@ -28,7 +28,12 @@ import jakarta.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import org.apache.struts2.components.Component; +import org.apache.struts2.util.ValueStackProvider; +import org.apache.struts2.views.util.ContextUtil; +import org.apache.velocity.context.AbstractContext; +import org.apache.velocity.context.Context; import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.context.InternalWrapperContext; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; @@ -57,8 +62,11 @@ public abstract class AbstractDirective extends Directive { protected abstract Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res); public boolean render(InternalContextAdapter ctx, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { - // get the bean - ValueStack stack = (ValueStack) ctx.get("stack"); + ValueStack stack = extractValueStack(ctx); + if (stack == null) { + // Fallback to assuming the ValueStack was put into the Velocity context (as is by default) + stack = (ValueStack) ctx.get(ContextUtil.STACK); + } HttpServletRequest req = (HttpServletRequest) stack.getContext().get(ServletActionContext.HTTP_REQUEST); HttpServletResponse res = (HttpServletResponse) stack.getContext().get(ServletActionContext.HTTP_RESPONSE); Component bean = getBean(stack, req, res); @@ -79,6 +87,27 @@ public abstract class AbstractDirective extends Directive { return true; } + private ValueStack extractValueStack(Context context) { + do { + if (context instanceof ValueStackProvider) { + return ((ValueStackProvider) context).getValueStack(); + } + context = extractContext(context); + } while (context != null); + + return null; + } + + private Context extractContext(Context context) { + if (context instanceof InternalWrapperContext) { + return ((InternalWrapperContext) context).getInternalUserContext(); + } + if (context instanceof AbstractContext) { + return ((AbstractContext) context).getChainedContext(); + } + return null; + } + /** * * Create a Map of properties that the user has passed in. For example: diff --git a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java index 6cd38c8aa..60490c6af 100644 --- a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java +++ b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java @@ -54,7 +54,7 @@ public class StrutsVelocityContextTest { @Test public void getChainedValue() { - when(chainedContext.internalGet("foo")).thenReturn("bar"); + when(chainedContext.get("foo")).thenReturn("bar"); assertEquals("bar", strutsVelocityContext.internalGet("foo")); } @@ -75,7 +75,7 @@ public class StrutsVelocityContextTest { when(stack.findValue("foo")).thenReturn("qux"); assertEquals("qux", strutsVelocityContext.internalGet("foo")); - when(chainedContext.internalGet("foo")).thenReturn("baz"); + when(chainedContext.get("foo")).thenReturn("baz"); assertEquals("baz", strutsVelocityContext.internalGet("foo")); strutsVelocityContext.put("foo", "bar"); diff --git a/pom.xml b/pom.xml index 3d75c51d4..259242da8 100644 --- a/pom.xml +++ b/pom.xml @@ -980,7 +980,7 @@ org.apache.commons commons-compress - 1.23.0 + 1.24.0
* This class implements the ActionConfigBuilder interface. - *
* 1. Loop over all the namespaces such as /foo and see if it has an action named index * 2. If an action doesn't exists in the parent namespace of the same name, create an action * in the parent namespace of the same name as the namespace that points to the index diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java index 4241f6ead..d18ca6bcf 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/StrutsVelocityContext.java @@ -19,6 +19,7 @@ package org.apache.struts2.views.velocity; import com.opensymphony.xwork2.util.ValueStack; +import org.apache.struts2.util.ValueStackProvider; import org.apache.velocity.VelocityContext; import java.util.ArrayList; @@ -26,7 +27,7 @@ import java.util.Arrays; import java.util.List; import java.util.function.Function; -public class StrutsVelocityContext extends VelocityContext { +public class StrutsVelocityContext extends VelocityContext implements ValueStackProvider { private final ValueStack stack; private final List chainedContexts; @@ -77,10 +78,10 @@ public class StrutsVelocityContext extends VelocityContext { } protected List> contextGetterList() { - return Arrays.asList(this::superGet, this::chainedContextGet, this::stackGet); + return Arrays.asList(this::superInternalGet, this::chainedContextGet, this::stackGet); } - protected Object superGet(String key) { + protected Object superInternalGet(String key) { return super.internalGet(key); } @@ -96,11 +97,16 @@ public class StrutsVelocityContext extends VelocityContext { return null; } for (VelocityContext chainedContext : chainedContexts) { - Object val = chainedContext.internalGet(key); + Object val = chainedContext.get(key); if (val != null) { return val; } } return null; } + + @Override + public ValueStack getValueStack() { + return stack; + } } diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java index e05fbe450..3e5996930 100644 --- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java +++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java @@ -28,7 +28,12 @@ import jakarta.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import org.apache.struts2.components.Component; +import org.apache.struts2.util.ValueStackProvider; +import org.apache.struts2.views.util.ContextUtil; +import org.apache.velocity.context.AbstractContext; +import org.apache.velocity.context.Context; import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.context.InternalWrapperContext; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; @@ -57,8 +62,11 @@ public abstract class AbstractDirective extends Directive { protected abstract Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res); public boolean render(InternalContextAdapter ctx, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { - // get the bean - ValueStack stack = (ValueStack) ctx.get("stack"); + ValueStack stack = extractValueStack(ctx); + if (stack == null) { + // Fallback to assuming the ValueStack was put into the Velocity context (as is by default) + stack = (ValueStack) ctx.get(ContextUtil.STACK); + } HttpServletRequest req = (HttpServletRequest) stack.getContext().get(ServletActionContext.HTTP_REQUEST); HttpServletResponse res = (HttpServletResponse) stack.getContext().get(ServletActionContext.HTTP_RESPONSE); Component bean = getBean(stack, req, res); @@ -79,6 +87,27 @@ public abstract class AbstractDirective extends Directive { return true; } + private ValueStack extractValueStack(Context context) { + do { + if (context instanceof ValueStackProvider) { + return ((ValueStackProvider) context).getValueStack(); + } + context = extractContext(context); + } while (context != null); + + return null; + } + + private Context extractContext(Context context) { + if (context instanceof InternalWrapperContext) { + return ((InternalWrapperContext) context).getInternalUserContext(); + } + if (context instanceof AbstractContext) { + return ((AbstractContext) context).getChainedContext(); + } + return null; + } + /** * * Create a Map of properties that the user has passed in. For example: diff --git a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java index 6cd38c8aa..60490c6af 100644 --- a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java +++ b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java @@ -54,7 +54,7 @@ public class StrutsVelocityContextTest { @Test public void getChainedValue() { - when(chainedContext.internalGet("foo")).thenReturn("bar"); + when(chainedContext.get("foo")).thenReturn("bar"); assertEquals("bar", strutsVelocityContext.internalGet("foo")); } @@ -75,7 +75,7 @@ public class StrutsVelocityContextTest { when(stack.findValue("foo")).thenReturn("qux"); assertEquals("qux", strutsVelocityContext.internalGet("foo")); - when(chainedContext.internalGet("foo")).thenReturn("baz"); + when(chainedContext.get("foo")).thenReturn("baz"); assertEquals("baz", strutsVelocityContext.internalGet("foo")); strutsVelocityContext.put("foo", "bar"); diff --git a/pom.xml b/pom.xml index 3d75c51d4..259242da8 100644 --- a/pom.xml +++ b/pom.xml @@ -980,7 +980,7 @@ org.apache.commons commons-compress - 1.23.0 + 1.24.0
* Create a Map of properties that the user has passed in. For example: diff --git a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java index 6cd38c8aa..60490c6af 100644 --- a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java +++ b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/StrutsVelocityContextTest.java @@ -54,7 +54,7 @@ public class StrutsVelocityContextTest { @Test public void getChainedValue() { - when(chainedContext.internalGet("foo")).thenReturn("bar"); + when(chainedContext.get("foo")).thenReturn("bar"); assertEquals("bar", strutsVelocityContext.internalGet("foo")); } @@ -75,7 +75,7 @@ public class StrutsVelocityContextTest { when(stack.findValue("foo")).thenReturn("qux"); assertEquals("qux", strutsVelocityContext.internalGet("foo")); - when(chainedContext.internalGet("foo")).thenReturn("baz"); + when(chainedContext.get("foo")).thenReturn("baz"); assertEquals("baz", strutsVelocityContext.internalGet("foo")); strutsVelocityContext.put("foo", "bar"); diff --git a/pom.xml b/pom.xml index 3d75c51d4..259242da8 100644 --- a/pom.xml +++ b/pom.xml @@ -980,7 +980,7 @@ org.apache.commons commons-compress - 1.23.0 + 1.24.0