diff --git a/core-common/src/main/java/org/glassfish/jersey/uri/internal/UriTemplateParser.java b/core-common/src/main/java/org/glassfish/jersey/uri/internal/UriTemplateParser.java index b438023bf2..0f5f759ae5 100644 --- a/core-common/src/main/java/org/glassfish/jersey/uri/internal/UriTemplateParser.java +++ b/core-common/src/main/java/org/glassfish/jersey/uri/internal/UriTemplateParser.java @@ -395,9 +395,14 @@ private int parseName(final CharacterIterator ci, int skipGroup) { // groupCounts.add(1 + skipGroup); if (variables.hasLength(0)) { - int len = TEMPLATE_VALUE_PATTERN.pattern().length() - 1; - String pattern = TEMPLATE_VALUE_PATTERN.pattern().substring(0, len) + '{' + variables.getLength(0) + '}'; - namePattern = Pattern.compile(pattern); + if (variables.getLength(0) != 0) { + int len = TEMPLATE_VALUE_PATTERN.pattern().length() - 1; + String pattern = TEMPLATE_VALUE_PATTERN.pattern().substring(0, len) + + '{' + variables.getLength(0) + '}'; + namePattern = Pattern.compile(pattern); + } else { + namePattern = TEMPLATE_VALUE_PATTERN; + } templateVariable.setLength(variables.getLength(0)); } else { namePattern = (!variables.hasRegexp(0)) @@ -462,7 +467,10 @@ private int parseName(final CharacterIterator ci, int skipGroup) { if (argIndex != 0) { regexBuilder.append(")"); } - regexBuilder.append("{0,1}"); + + if (!variables.hasRegexp(argIndex)) { + regexBuilder.append("{0,1}"); + } argIndex++; groupCounts.add(2); @@ -571,6 +579,7 @@ private void parse(CharacterIterator ci, String template) { StringBuilder regexBuilder = new StringBuilder(); State state = State.TEMPLATE; + State previousState; boolean star = false; boolean whiteSpace = false; boolean ignoredLastComma = false; @@ -579,6 +588,7 @@ private void parse(CharacterIterator ci, String template) { int regExpRound = 0; // ( boolean reqExpSlash = false; // \ while ((state.value & (State.ERROR.value | State.EXIT.value)) == 0) { + previousState = state; c = ci.next(); // "\\{(\\w[-\\w\\.]*) if (Character.isLetterOrDigit(c)) { @@ -702,8 +712,8 @@ private void parse(CharacterIterator ci, String template) { regexps.add(regex); } } else { - regexps.add(null); - lengths.add(null); + regexps.add(previousState == State.REGEXP ? "" : null); + lengths.add(previousState == State.REGEXP ? 0 : null); } names.add(nameBuilder.toString()); diff --git a/core-common/src/test/java/org/glassfish/jersey/uri/UriTemplateTest.java b/core-common/src/test/java/org/glassfish/jersey/uri/UriTemplateTest.java index 7846c113af..cdd965bc9f 100644 --- a/core-common/src/test/java/org/glassfish/jersey/uri/UriTemplateTest.java +++ b/core-common/src/test/java/org/glassfish/jersey/uri/UriTemplateTest.java @@ -31,6 +31,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; + import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -257,7 +259,7 @@ void _testMatching(final String template, final String uri, final String... valu final Map m = new HashMap(); boolean isMatch = t.match(uri, m); - assertTrue(isMatch); + assertTrue(isMatch, "No match for '" + uri + "' & params '" + Arrays.toString(values) + "`"); assertEquals(values.length, t.getTemplateVariables().size()); final Iterator names = t.getTemplateVariables().iterator(); @@ -982,6 +984,7 @@ void testRfc6570MultiplePathArgs() { _testTemplateNames("/{a,b,c}", "a", "b", "c"); _testMatching("/uri/{a}", "/uri/hello", "hello"); _testMatching("/uri/{a,b}", "/uri/hello,world", "hello", "world"); + _testMatching("/uri/{a,b}", "/uri/x", "x", null); _testMatching("/uri{?a,b}", "/uri?a=hello&b=world", "hello", "world"); _testMatching("/uri/{a,b,c}", "/uri/hello,world,!", "hello", "world", "!"); _testMatching("/uri/{a,b,c}", "/uri/hello,world", "hello", "world", null); @@ -989,6 +992,12 @@ void testRfc6570MultiplePathArgs() { _testMatching("/uri/{a,b,c}", "/uri/", null, null, null); } + @Test + public void testRegularExpressionIsNotOptional() { + Assertions.assertThrows(AssertionFailedError.class, + () -> _testMatching("/{name: [a-z0-9]{3,128}}", "/", new String[]{null})); + } + @Test void testRfc6570PathLength() { _testMatching("/uri/{a:5}", "/uri/hello", "hello");