UriPattern extends SmithyPattern { public static UriPattern parse(String uri) { if (uri.endsWith("?")) { throw new InvalidUriPatternException("URI patterns must not end with '?'. Found " + uri); } else if (!uri.startsWith("/")) { throw new InvalidUriPatternException("URI pattern must start with '/'. Found " + uri); } else if (uri.contains("#")) { throw new InvalidUriPatternException("URI pattern must not contain a fragment. Found " + uri); } String[] parts = uri.split(java.util.regex.Pattern.quote("?"), 2); String[] unparsedSegments = parts[0].split(java.util.regex.Pattern.quote("/")); List<Segment> segments = new ArrayList<>(); int offset = 1; for (int i = 1; i < unparsedSegments.length; i++) { String segment = unparsedSegments[i]; segments.add(Segment.parse(segment, offset)); offset += segment.length(); } Map<String, String> queryLiterals = new LinkedHashMap<>(); if (parts.length == 2) { if (parts[1].contains("{") || parts[1].contains("}")) { throw new InvalidUriPatternException("URI labels must not appear in the query string. Found " + uri); } for (String kvp : parts[1].split(java.util.regex.Pattern.quote("&"))) { String[] parameterParts = kvp.split("=", 2); String actualKey = parameterParts[0]; if (queryLiterals.containsKey(actualKey)) { throw new InvalidUriPatternException("Literal query parameters must not be repeated: " + uri); } queryLiterals.put(actualKey, parameterParts.length == 2 ? parameterParts[1] : ""); } } return new UriPattern(builder().pattern(uri).segments(segments), queryLiterals); } private  UriPattern(Builder builder, Map<String, String> queryLiterals); static UriPattern parse(String uri); Map<String, String> getQueryLiterals(); Optional<String> getQueryLiteralValue(String parameter); boolean conflictsWith(UriPattern otherPattern); List<Pair<Segment, Segment>> getConflictingLabelSegments(UriPattern otherPattern); @Override boolean equals(Object other); @Override int hashCode();  }
@Test public void labelsMustStartWithSlash() { Throwable thrown = Assertions.assertThrows(InvalidUriPatternException.class, () -> UriPattern.parse("foo")); assertThat(thrown.getMessage(), containsString("URI pattern must start with '/'")); }
@Test public void labelsMustNotEndWithQuestionMark() { Throwable thrown = Assertions.assertThrows(InvalidUriPatternException.class, () -> UriPattern.parse("/foo?")); assertThat(thrown.getMessage(), containsString("URI patterns must not end with '?'")); }
@Test public void patternsMustNotContainFragments() { Throwable thrown = Assertions.assertThrows(InvalidUriPatternException.class, () -> UriPattern.parse("/foo#bam")); assertThat(thrown.getMessage(), containsString("URI pattern must not contain a fragment")); }
@Test public void labelsMustNotAppearInQueryString() { Throwable thrown = Assertions.assertThrows(InvalidUriPatternException.class, () -> { UriPattern.parse("/baz?bam={boozled}"); }); assertThat(thrown.getMessage(), containsString("URI labels must not appear in the query string")); }
@Test public void detectsCaseSensitiveDuplicateQueryStringLiterals() { Throwable thrown = Assertions.assertThrows(InvalidUriPatternException.class, () -> { UriPattern.parse("/foo?baz=bar&baz=bam"); }); assertThat(thrown.getMessage(), containsString("Literal query parameters must not be repeated")); }