Merge branch '6.2.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -37,13 +37,24 @@ public abstract class PatternMatchUtils {
|
|||||||
* @return whether the String matches the given pattern
|
* @return whether the String matches the given pattern
|
||||||
*/
|
*/
|
||||||
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
|
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
|
||||||
|
return simpleMatch(pattern, str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of {@link #simpleMatch(String, String)} that ignores upper/lower case.
|
||||||
|
*/
|
||||||
|
public static boolean simpleMatchIgnoreCase(@Nullable String pattern, @Nullable String str) {
|
||||||
|
return simpleMatch(pattern, str, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean simpleMatch(@Nullable String pattern, @Nullable String str, boolean ignoreCase) {
|
||||||
if (pattern == null || str == null) {
|
if (pattern == null || str == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int firstIndex = pattern.indexOf('*');
|
int firstIndex = pattern.indexOf('*');
|
||||||
if (firstIndex == -1) {
|
if (firstIndex == -1) {
|
||||||
return pattern.equals(str);
|
return (ignoreCase ? pattern.equalsIgnoreCase(str) : pattern.equals(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstIndex == 0) {
|
if (firstIndex == 0) {
|
||||||
@@ -52,25 +63,43 @@ public abstract class PatternMatchUtils {
|
|||||||
}
|
}
|
||||||
int nextIndex = pattern.indexOf('*', 1);
|
int nextIndex = pattern.indexOf('*', 1);
|
||||||
if (nextIndex == -1) {
|
if (nextIndex == -1) {
|
||||||
return str.endsWith(pattern.substring(1));
|
String part = pattern.substring(1);
|
||||||
|
return (ignoreCase ? StringUtils.endsWithIgnoreCase(str, part) : str.endsWith(part));
|
||||||
}
|
}
|
||||||
String part = pattern.substring(1, nextIndex);
|
String part = pattern.substring(1, nextIndex);
|
||||||
if (part.isEmpty()) {
|
if (part.isEmpty()) {
|
||||||
return simpleMatch(pattern.substring(nextIndex), str);
|
return simpleMatch(pattern.substring(nextIndex), str, ignoreCase);
|
||||||
}
|
}
|
||||||
int partIndex = str.indexOf(part);
|
int partIndex = indexOf(str, part, 0, ignoreCase);
|
||||||
while (partIndex != -1) {
|
while (partIndex != -1) {
|
||||||
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
|
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()), ignoreCase)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
partIndex = str.indexOf(part, partIndex + 1);
|
partIndex = indexOf(str, part, partIndex + 1, ignoreCase);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (str.length() >= firstIndex &&
|
return (str.length() >= firstIndex &&
|
||||||
pattern.startsWith(str.substring(0, firstIndex)) &&
|
checkStartsWith(pattern, str, firstIndex, ignoreCase) &&
|
||||||
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
|
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex), ignoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkStartsWith(String pattern, String str, int index, boolean ignoreCase) {
|
||||||
|
String part = str.substring(0, index);
|
||||||
|
return (ignoreCase ? StringUtils.startsWithIgnoreCase(pattern, part) : pattern.startsWith(part));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(String str, String otherStr, int startIndex, boolean ignoreCase) {
|
||||||
|
if (!ignoreCase) {
|
||||||
|
return str.indexOf(otherStr, startIndex);
|
||||||
|
}
|
||||||
|
for (int i = startIndex; i <= (str.length() - otherStr.length()); i++) {
|
||||||
|
if (str.regionMatches(true, i, otherStr, 0, otherStr.length())) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,4 +123,18 @@ public abstract class PatternMatchUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of {@link #simpleMatch(String[], String)} that ignores upper/lower case.
|
||||||
|
*/
|
||||||
|
public static boolean simpleMatchIgnoreCase(@Nullable String[] patterns, @Nullable String str) {
|
||||||
|
if (patterns != null) {
|
||||||
|
for (String pattern : patterns) {
|
||||||
|
if (simpleMatch(pattern, str, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -53,18 +53,22 @@ class PatternMatchUtilsTests {
|
|||||||
assertMatches(new String[] { null, "" }, "");
|
assertMatches(new String[] { null, "" }, "");
|
||||||
assertMatches(new String[] { null, "123" }, "123");
|
assertMatches(new String[] { null, "123" }, "123");
|
||||||
assertMatches(new String[] { null, "*" }, "123");
|
assertMatches(new String[] { null, "*" }, "123");
|
||||||
|
|
||||||
|
testMixedCaseMatch("abC", "Abc");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void startsWith() {
|
void startsWith() {
|
||||||
assertMatches("get*", "getMe");
|
assertMatches("get*", "getMe");
|
||||||
assertDoesNotMatch("get*", "setMe");
|
assertDoesNotMatch("get*", "setMe");
|
||||||
|
testMixedCaseMatch("geT*", "GetMe");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void endsWith() {
|
void endsWith() {
|
||||||
assertMatches("*Test", "getMeTest");
|
assertMatches("*Test", "getMeTest");
|
||||||
assertDoesNotMatch("*Test", "setMe");
|
assertDoesNotMatch("*Test", "setMe");
|
||||||
|
testMixedCaseMatch("*TeSt", "getMeTesT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -74,6 +78,10 @@ class PatternMatchUtilsTests {
|
|||||||
assertMatches("*stuff*", "stuffTest");
|
assertMatches("*stuff*", "stuffTest");
|
||||||
assertMatches("*stuff*", "getstuff");
|
assertMatches("*stuff*", "getstuff");
|
||||||
assertMatches("*stuff*", "stuff");
|
assertMatches("*stuff*", "stuff");
|
||||||
|
testMixedCaseMatch("*stuff*", "getStuffTest");
|
||||||
|
testMixedCaseMatch("*stuff*", "StuffTest");
|
||||||
|
testMixedCaseMatch("*stuff*", "getStuff");
|
||||||
|
testMixedCaseMatch("*stuff*", "Stuff");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -82,6 +90,8 @@ class PatternMatchUtilsTests {
|
|||||||
assertMatches("on*Event", "onEvent");
|
assertMatches("on*Event", "onEvent");
|
||||||
assertDoesNotMatch("3*3", "3");
|
assertDoesNotMatch("3*3", "3");
|
||||||
assertMatches("3*3", "33");
|
assertMatches("3*3", "33");
|
||||||
|
testMixedCaseMatch("on*Event", "OnMyEvenT");
|
||||||
|
testMixedCaseMatch("on*Event", "OnEvenT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -122,18 +132,27 @@ class PatternMatchUtilsTests {
|
|||||||
|
|
||||||
private void assertMatches(String pattern, String str) {
|
private void assertMatches(String pattern, String str) {
|
||||||
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue();
|
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue();
|
||||||
|
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertDoesNotMatch(String pattern, String str) {
|
private void assertDoesNotMatch(String pattern, String str) {
|
||||||
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
|
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
|
||||||
|
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testMixedCaseMatch(String pattern, String str) {
|
||||||
|
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
|
||||||
|
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertMatches(String[] patterns, String str) {
|
private void assertMatches(String[] patterns, String str) {
|
||||||
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue();
|
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue();
|
||||||
|
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertDoesNotMatch(String[] patterns, String str) {
|
private void assertDoesNotMatch(String[] patterns, String str) {
|
||||||
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse();
|
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse();
|
||||||
|
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -443,11 +443,10 @@ final class HierarchicalUriComponents extends UriComponents {
|
|||||||
UriTemplateVariables queryVariables = new QueryUriTemplateVariables(variables);
|
UriTemplateVariables queryVariables = new QueryUriTemplateVariables(variables);
|
||||||
this.queryParams.forEach((key, values) -> {
|
this.queryParams.forEach((key, values) -> {
|
||||||
String name = expandUriComponent(key, queryVariables, this.variableEncoder);
|
String name = expandUriComponent(key, queryVariables, this.variableEncoder);
|
||||||
List<String> expandedValues = new ArrayList<>(values.size());
|
List<String> expandedValues = result.computeIfAbsent(name, k -> new ArrayList<>(values.size()));
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
expandedValues.add(expandUriComponent(value, queryVariables, this.variableEncoder));
|
expandedValues.add(expandUriComponent(value, queryVariables, this.variableEncoder));
|
||||||
}
|
}
|
||||||
result.put(name, expandedValues);
|
|
||||||
});
|
});
|
||||||
return CollectionUtils.unmodifiableMultiValueMap(result);
|
return CollectionUtils.unmodifiableMultiValueMap(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -629,6 +629,17 @@ class UriComponentsBuilderTests {
|
|||||||
assertThat(uri.toString()).isEqualTo("ws://example.org:7777/path?q=1#foo");
|
assertThat(uri.toString()).isEqualTo("ws://example.org:7777/path?q=1#foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest // gh-34783
|
||||||
|
@EnumSource
|
||||||
|
void parseBuildAndExpandQueryParamWithSameName(ParserType parserType) {
|
||||||
|
UriComponents result = UriComponentsBuilder
|
||||||
|
.fromUriString("/?{pk1}={pv1}&{pk2}={pv2}", parserType)
|
||||||
|
.buildAndExpand("k1", "v1", "k1", "v2");
|
||||||
|
|
||||||
|
assertThat(result.getQuery()).isEqualTo("k1=v1&k1=v2");
|
||||||
|
assertThat(result.getQueryParams()).containsExactly(Map.entry("k1", List.of("v1", "v2")));
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@EnumSource
|
@EnumSource
|
||||||
void buildAndExpandOpaque(ParserType parserType) {
|
void buildAndExpandOpaque(ParserType parserType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user