Skip to content

Commit

Permalink
Fix bug in common path prefix calculation (#20310)
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Quinn <[email protected]>
  • Loading branch information
tjquinno authored Dec 14, 2024
1 parent 1a3d7d4 commit d55a41e
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.prefs.BackingStoreException;
Expand Down Expand Up @@ -352,7 +353,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
Scan the paths of all the operations, computing the longest common prefix. Then compute and set the path suffix
for each operation.
*/
String commonPathPrefixForApi = StringUtils.getCommonPrefix(objs.getOperations().getOperation()
String commonPathPrefixForApi = commonPathPrefix(objs.getOperations().getOperation()
.stream()
.map(op -> op.path)
.map(path -> path.charAt(0) != '/' ? "/" + path : path )
Expand Down Expand Up @@ -450,6 +451,46 @@ protected String rootJavaEEPackage() {
return rootJavaEEPackage;
}

static String commonPathPrefix(String[] paths) {

if (paths.length == 0) {
return "/";
}

// Start out with the first path as the longest common prefix. The eventual longest common
// prefix can be no longer than the first path, so as we check other paths we simply
// revise the number of matching segments we have.
String[] commonSegments = stripAnyLeadingSlash(paths[0]).split("/");
int commonSegmentsCount = commonSegments.length;

// Examine the remaining paths.
for (int i = 1; i < paths.length; i++) {
String[] segments = stripAnyLeadingSlash(paths[i]).split("/");

// Check each segment of this next path against the common segments we have so far.
int segmentIndex = 0;
while (segmentIndex < Math.min(commonSegmentsCount, segments.length)
&& commonSegments[segmentIndex].equals(segments[segmentIndex])) {
segmentIndex++;
}
commonSegmentsCount = segmentIndex;
if (commonSegmentsCount == 0) {
break;
}
}
StringJoiner commonPath = new StringJoiner("/", "/", "");
commonPath.setEmptyValue("/");

for (int i = 0; i < commonSegmentsCount; i++) {
commonPath.add(commonSegments[i]);
}
return commonPath.toString();
}

private static String stripAnyLeadingSlash(String path) {
return path.startsWith("/") ? path.substring(1) : path;
}

/**
* Prepares a map of predefined HTTP status code constants.
* <p>
Expand Down Expand Up @@ -716,9 +757,9 @@ static class VersionUtil {

private static final String DEFAULT_VERSIONS = "<data>\n" +
" <archetypes>\n" +
" <version>2.6.5</version>\n" +
" <version>3.2.7</version>\n" +
" <version>4.0.9</version>\n" +
" <version>2.6.10</version>\n" +
" <version>3.2.11</version>\n" +
" <version>4.1.4</version>\n" +
" </archetypes>\n" +
"</data>";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,56 @@ void testVersionNotInDefaultListWithNoNetwork() {
List.of("4.0.10", "3.2.1", "3.2.0", "2.0.4", "1.2.3", "1.2.2", "1.1.0")))
.isEqualTo("4.0.11-SNAPSHOT");
}

@Test
void checkCommonPathWithPathParams() {
String[] paths = List.of("/users/{userId}/profile",
"/users/{userId}/problems",
"/users/{userEmail}",
"/users/{username}")
.toArray(new String[0]);

String commonPrefix = JavaHelidonCommonCodegen.commonPathPrefix(paths);
assertThat(commonPrefix).isEqualTo("/users");
}

@Test
void checkCommonPathWithMultipleCommonLevels() {
String[] paths = List.of("/users/a/x",
"/users/a/y",
"/users/a/z")
.toArray(new String[0]);

String commonPrefix = JavaHelidonCommonCodegen.commonPathPrefix(paths);
assertThat(commonPrefix).isEqualTo("/users/a");
}

@Test
void checkNoCommonSegments() {
String[] paths = List.of("/a/x",
"/b/y",
"/c")
.toArray(new String[0]);

String commonPrefix = JavaHelidonCommonCodegen.commonPathPrefix(paths);
assertThat(commonPrefix).isEqualTo("/");
}

@Test
void checkSinglePathCommonSegments() {
String commonPrefix = JavaHelidonCommonCodegen.commonPathPrefix(new String[0]);
assertThat(commonPrefix).isEqualTo("/");
}

@Test
void checkMixedWithPathParam() {
String[] paths = List.of("/store/order/{order_id}",
"/store/inventory",
"/store/order/{order_id}",
"/store/order")
.toArray(new String[0]);

String commonPrefix = JavaHelidonCommonCodegen.commonPathPrefix(paths);
assertThat(commonPrefix).isEqualTo("/store");
}
}

0 comments on commit d55a41e

Please sign in to comment.