This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5310-fragment
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 4a85b6c4f488a1b44038eb402fc48999e4f44899
Author: Lukasz Lenart <lukaszlen...@apache.org>
AuthorDate: Tue Jun 20 21:23:57 2023 +0200

    WW-5310 Deprecates the old API in favour of new one
---
 .../struts2/components/ServletUrlRenderer.java     | 16 ++--
 .../struts2/result/ServletDispatcherResult.java    |  7 +-
 .../org/apache/struts2/url/QueryStringParser.java  | 38 ++++++++-
 .../struts2/url/StrutsQueryStringParser.java       | 97 +++++++++++++++++-----
 .../struts2/url/StrutsQueryStringParserTest.java   | 23 ++---
 5 files changed, 140 insertions(+), 41 deletions(-)

diff --git 
a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java 
b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
index d5281a8a0..853c0a389 100644
--- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
+++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
@@ -159,10 +159,10 @@ public class ServletUrlRenderer implements UrlRenderer {
             }
         }
 
-        Map<String, Object> actionParams = null;
+        QueryStringParser.Result queryStringResult = queryStringParser.empty();
         if (action != null && action.indexOf('?') > 0) {
             String queryString = action.substring(action.indexOf('?') + 1);
-            actionParams = queryStringParser.parse(queryString, false);
+            queryStringResult = queryStringParser.parse(queryString);
             action = action.substring(0, action.indexOf('?'));
         }
 
@@ -176,7 +176,7 @@ public class ServletUrlRenderer implements UrlRenderer {
 
             ActionMapping mapping = new ActionMapping(actionName, namespace, 
actionMethod, formComponent.parameters);
             String result = 
urlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping),
-                formComponent.request, formComponent.response, actionParams, 
scheme, formComponent.includeContext, true, false, false);
+                formComponent.request, formComponent.response, 
queryStringResult.getQueryParams(), scheme, formComponent.includeContext, true, 
false, false);
             formComponent.addParameter("action", result);
 
             // let's try to get the actual action class and name
@@ -213,7 +213,7 @@ public class ServletUrlRenderer implements UrlRenderer {
                 LOG.warn("No configuration found for the specified action: 
'{}' in namespace: '{}'. Form action defaulting to 'action' attribute's literal 
value.", actionName, namespace);
             }
 
-            String result = urlHelper.buildUrl(action, formComponent.request, 
formComponent.response, actionParams, scheme, formComponent.includeContext, 
true);
+            String result = urlHelper.buildUrl(action, formComponent.request, 
formComponent.response, queryStringResult.getQueryParams(), scheme, 
formComponent.includeContext, true);
             formComponent.addParameter("action", result);
 
             // namespace: cut out anything between the start and the last /
@@ -291,7 +291,11 @@ public class ServletUrlRenderer implements UrlRenderer {
 
     private void includeGetParameters(UrlProvider urlComponent) {
         String query = extractQueryString(urlComponent);
-        mergeRequestParameters(urlComponent.getValue(), 
urlComponent.getParameters(), queryStringParser.parse(query, false));
+        QueryStringParser.Result result = queryStringParser.parse(query);
+        mergeRequestParameters(urlComponent.getValue(), 
urlComponent.getParameters(), result.getQueryParams());
+        if (!result.getQueryFragment().isEmpty()) {
+            urlComponent.setAnchor(result.getQueryFragment());
+        }
     }
 
     private String extractQueryString(UrlProvider urlComponent) {
@@ -339,7 +343,7 @@ public class ServletUrlRenderer implements UrlRenderer {
         if (StringUtils.contains(value, "?")) {
             String queryString = value.substring(value.indexOf('?') + 1);
 
-            mergedParams = queryStringParser.parse(queryString, false);
+            mergedParams = new 
LinkedHashMap<>(queryStringParser.parse(queryString).getQueryParams());
             for (Map.Entry<String, ?> entry : contextParameters.entrySet()) {
                 if (!mergedParams.containsKey(entry.getKey())) {
                     mergedParams.put(entry.getKey(), entry.getValue());
diff --git 
a/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java 
b/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
index 6bc86725d..d863a890b 100644
--- a/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
+++ b/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
@@ -33,7 +33,6 @@ import javax.servlet.RequestDispatcher;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.PageContext;
-import java.util.Map;
 
 /**
  * <!-- START SNIPPET: description -->
@@ -140,9 +139,9 @@ public class ServletDispatcherResult extends 
StrutsResultSupport {
             if (StringUtils.isNotEmpty(finalLocation) && 
finalLocation.indexOf('?') > 0) {
                 String queryString = 
finalLocation.substring(finalLocation.indexOf('?') + 1);
                 HttpParameters parameters = getParameters(invocation);
-                Map<String, Object> queryParams = 
queryStringParser.parse(queryString, true);
-                if (queryParams != null && !queryParams.isEmpty()) {
-                    parameters = 
HttpParameters.create(queryParams).withParent(parameters).build();
+                QueryStringParser.Result queryParams = 
queryStringParser.parse(queryString);
+                if (!queryParams.isEmpty()) {
+                    parameters = 
HttpParameters.create(queryParams.getQueryParams()).withParent(parameters).build();
                     
invocation.getInvocationContext().withParameters(parameters);
                     // put to extraContext, see Dispatcher#createContextMap
                     
invocation.getInvocationContext().getContextMap().put("parameters", parameters);
diff --git a/core/src/main/java/org/apache/struts2/url/QueryStringParser.java 
b/core/src/main/java/org/apache/struts2/url/QueryStringParser.java
index 0f48cd293..84cfa45ed 100644
--- a/core/src/main/java/org/apache/struts2/url/QueryStringParser.java
+++ b/core/src/main/java/org/apache/struts2/url/QueryStringParser.java
@@ -22,11 +22,47 @@ import java.io.Serializable;
 import java.util.Map;
 
 /**
- * Used to parse Http Query String into a Map of parameters
+ * Used to parse Http Query String into a map of parameters with support for 
fragment
+ *
  * @since Struts 6.1.0
  */
 public interface QueryStringParser extends Serializable {
 
+    /**
+     * @deprecated since Struts 6.2.0, use {@link #parse(String)} instead
+     */
+    @Deprecated
     Map<String, Object> parse(String queryString, boolean forceValueArray);
 
+    /**
+     * @param queryString a query string to parse
+     * @return a {@link Result} of parsing the query string
+     * @since Struts 6.2.0
+     */
+    Result parse(String queryString);
+
+    /**
+     * Return an empty {@link Result}
+     * @return empty result
+     */
+    Result empty();
+
+    /**
+     * Represents result of parsing query string by implementation of {@link 
QueryStringParser}
+     */
+    interface Result {
+
+        Result addParam(String name, String value);
+
+        Result withQueryFragment(String queryFragment);
+
+        Map<String, Object> getQueryParams();
+
+        String getQueryFragment();
+
+        boolean contains(String name);
+
+        boolean isEmpty();
+    }
+
 }
diff --git 
a/core/src/main/java/org/apache/struts2/url/StrutsQueryStringParser.java 
b/core/src/main/java/org/apache/struts2/url/StrutsQueryStringParser.java
index 4c31d4885..ec7521560 100644
--- a/core/src/main/java/org/apache/struts2/url/StrutsQueryStringParser.java
+++ b/core/src/main/java/org/apache/struts2/url/StrutsQueryStringParser.java
@@ -43,12 +43,17 @@ public class StrutsQueryStringParser implements 
QueryStringParser {
 
     @Override
     public Map<String, Object> parse(String queryString, boolean 
forceValueArray) {
+        return parse(queryString).getQueryParams();
+    }
+
+    @Override
+    public Result parse(String queryString) {
         if (StringUtils.isEmpty(queryString)) {
             LOG.debug("Query String is empty, returning an empty map");
-            return Collections.emptyMap();
+            return this.empty();
         }
 
-        Map<String, Object> queryParams = new LinkedHashMap<>();
+        Result queryParams = StrutsQueryStringParserResult.create();
         String[] params = extractParams(queryString);
         for (String param : params) {
             if (StringUtils.isBlank(param)) {
@@ -64,9 +69,14 @@ public class StrutsQueryStringParser implements 
QueryStringParser {
             } else {
                 paramName = param;
             }
-            extractParam(paramName, paramValue, queryParams, forceValueArray);
+            queryParams = extractParam(paramName, paramValue, queryParams);
         }
-        return queryParams;
+        return queryParams.withQueryFragment(extractFragment(queryString));
+    }
+
+    @Override
+    public Result empty() {
+        return new StrutsQueryStringParserResult(Collections.emptyMap(), "");
     }
 
     private String[] extractParams(String queryString) {
@@ -81,27 +91,76 @@ public class StrutsQueryStringParser implements 
QueryStringParser {
         return params;
     }
 
-    private void extractParam(String paramName, String paramValue, Map<String, 
Object> queryParams, boolean forceValueArray) {
+    private Result extractParam(String paramName, String paramValue, Result 
queryParams) {
         String decodedParamName = decoder.decode(paramName, true);
         String decodedParamValue = decoder.decode(paramValue, true);
+        return queryParams.addParam(decodedParamName, decodedParamValue);
+    }
 
-        if (queryParams.containsKey(decodedParamName) || forceValueArray) {
-            // WW-1619 append new param value to existing value(s)
-            Object currentParam = queryParams.get(decodedParamName);
-            if (currentParam instanceof String) {
-                queryParams.put(decodedParamName, new String[]{(String) 
currentParam, decodedParamValue});
-            } else {
-                String[] currentParamValues = (String[]) currentParam;
-                if (currentParamValues != null) {
-                    List<String> paramList = new 
ArrayList<>(Arrays.asList(currentParamValues));
-                    paramList.add(decodedParamValue);
-                    queryParams.put(decodedParamName, paramList.toArray(new 
String[0]));
+    private String extractFragment(String queryString) {
+        int fragmentIndex = queryString.lastIndexOf("#");
+        if (fragmentIndex > -1) {
+            return queryString.substring(fragmentIndex + 1);
+        }
+        return "";
+    }
+
+    public static class StrutsQueryStringParserResult implements Result {
+
+        private final Map<String, Object> queryParams;
+        private String queryFragment;
+
+        static Result create() {
+            return new StrutsQueryStringParserResult(new LinkedHashMap<>(), 
"");
+        }
+
+        private StrutsQueryStringParserResult(Map<String, Object> queryParams, 
String queryFragment) {
+            this.queryParams = queryParams;
+            this.queryFragment = queryFragment;
+        }
+
+        public Result addParam(String name, String value) {
+            if (queryParams.containsKey(name)) {
+                // WW-1619 append new param value to existing value(s)
+                Object currentParam = queryParams.get(name);
+                if (currentParam instanceof String) {
+                    queryParams.put(name, new String[]{(String) currentParam, 
value});
                 } else {
-                    queryParams.put(decodedParamName, new 
String[]{decodedParamValue});
+                    String[] currentParamValues = (String[]) currentParam;
+                    if (currentParamValues != null) {
+                        List<String> paramList = new 
ArrayList<>(Arrays.asList(currentParamValues));
+                        paramList.add(value);
+                        queryParams.put(name, paramList.toArray(new 
String[0]));
+                    } else {
+                        queryParams.put(name, new String[]{value});
+                    }
                 }
+            } else {
+                queryParams.put(name, value);
             }
-        } else {
-            queryParams.put(decodedParamName, decodedParamValue);
+
+            return this;
+        }
+
+        public Result withQueryFragment(String queryFragment) {
+            this.queryFragment = queryFragment;
+            return this;
+        }
+
+        public Map<String, Object> getQueryParams() {
+            return Collections.unmodifiableMap(queryParams);
+        }
+
+        public String getQueryFragment() {
+            return queryFragment;
+        }
+
+        public boolean contains(String name) {
+            return queryParams.containsKey(name);
+        }
+
+        public boolean isEmpty() {
+            return queryParams.isEmpty();
         }
     }
 }
diff --git 
a/core/src/test/java/org/apache/struts2/url/StrutsQueryStringParserTest.java 
b/core/src/test/java/org/apache/struts2/url/StrutsQueryStringParserTest.java
index 93fd9bbaa..c8183725b 100644
--- a/core/src/test/java/org/apache/struts2/url/StrutsQueryStringParserTest.java
+++ b/core/src/test/java/org/apache/struts2/url/StrutsQueryStringParserTest.java
@@ -35,7 +35,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void testParseQuery() {
-        Map<String, Object> result = 
parser.parse("aaa=aaaval&bbb=bbbval&ccc=&%3Ca%22%3E=%3Cval%3E", false);
+        Map<String, Object> result = 
parser.parse("aaa=aaaval&bbb=bbbval&ccc=&%3Ca%22%3E=%3Cval%3E").getQueryParams();
 
         assertEquals("aaaval", result.get("aaa"));
         assertEquals("bbbval", result.get("bbb"));
@@ -45,7 +45,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void testParseQueryIntoArray() {
-        Map<String, Object> result = parser.parse("a=1&a=2&a=3", true);
+        Map<String, Object> result = 
parser.parse("a=1&a=2&a=3").getQueryParams();
 
         Object actual = result.get("a");
         assertThat(actual).isInstanceOf(String[].class);
@@ -54,7 +54,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void testParseEmptyQuery() {
-        Map<String, Object> result = parser.parse("", false);
+        Map<String, Object> result = parser.parse("").getQueryParams();
 
         assertNotNull(result);
         assertEquals(0, result.size());
@@ -62,7 +62,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void testParseNullQuery() {
-        Map<String, Object> result = parser.parse(null, false);
+        Map<String, Object> result = parser.parse(null).getQueryParams();
 
         assertNotNull(result);
         assertEquals(0, result.size());
@@ -70,7 +70,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void testDecodeSpacesInQueryString() {
-        Map<String, Object> queryParameters = 
parser.parse("name=value+with+space", false);
+        Map<String, Object> queryParameters = 
parser.parse("name=value+with+space").getQueryParams();
 
         assertTrue(queryParameters.containsKey("name"));
         assertEquals("value with space", queryParameters.get("name"));
@@ -78,7 +78,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void shouldProperlySplitParamsWithDoubleEqualSign() {
-        Map<String, Object> queryParameters = 
parser.parse("id1=n123=&id2=n3456", false);
+        Map<String, Object> queryParameters = 
parser.parse("id1=n123=&id2=n3456").getQueryParams();
 
         assertTrue(queryParameters.containsKey("id1"));
         assertTrue(queryParameters.containsKey("id2"));
@@ -88,7 +88,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void shouldHandleParamWithNoValue1() {
-        Map<String, Object> queryParameters = parser.parse("paramNoValue", 
false);
+        Map<String, Object> queryParameters = 
parser.parse("paramNoValue").getQueryParams();
 
         assertTrue(queryParameters.containsKey("paramNoValue"));
         assertEquals("", queryParameters.get("paramNoValue"));
@@ -96,7 +96,7 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void shouldHandleParamWithNoValue2() {
-        Map<String, Object> queryParameters = 
parser.parse("paramNoValue&param1=1234", false);
+        Map<String, Object> queryParameters = 
parser.parse("paramNoValue&param1=1234").getQueryParams();
 
         assertTrue(queryParameters.containsKey("paramNoValue"));
         assertTrue(queryParameters.containsKey("param1"));
@@ -105,10 +105,11 @@ public class StrutsQueryStringParserTest {
 
     @Test
     public void shouldHandleParamAndFragment() {
-        Map<String, Object> queryParameters = parser.parse("param1=1234#test", 
false);
+        QueryStringParser.Result queryParameters = 
parser.parse("param1=1234#test");
 
-        assertTrue(queryParameters.containsKey("param1"));
-        assertEquals("1234", queryParameters.get("param1"));
+        assertTrue(queryParameters.getQueryParams().containsKey("param1"));
+        assertEquals("1234", queryParameters.getQueryParams().get("param1"));
+        assertEquals("test", queryParameters.getQueryFragment());
     }
 
     @Before

Reply via email to