Skip to content

Commit

Permalink
Fix parsing UrlTemplates
Browse files Browse the repository at this point in the history
  • Loading branch information
altro3 committed Aug 9, 2024
1 parent 018fd5c commit ea81b0f
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
import static io.micronaut.openapi.visitor.SchemaUtils.setOperationOnPathItem;
import static io.micronaut.openapi.visitor.SchemaUtils.setSpecVersion;
import static io.micronaut.openapi.visitor.StringUtil.CLOSE_BRACE;
import static io.micronaut.openapi.visitor.StringUtil.DOLLAR;
import static io.micronaut.openapi.visitor.StringUtil.OPEN_BRACE;
import static io.micronaut.openapi.visitor.StringUtil.THREE_DOTS;
import static io.micronaut.openapi.visitor.Utils.DEFAULT_MEDIA_TYPES;
Expand Down Expand Up @@ -533,6 +534,8 @@ private void addParamsByUriTemplate(String path, Map<String, UriMatchVariable> p
var pathVar = entry.getValue();
if (pathVar.isExploded()
|| !path.contains(OPEN_BRACE + varName + CLOSE_BRACE)
// skip placeholders
|| path.contains(DOLLAR + OPEN_BRACE + varName + CLOSE_BRACE)
|| isAlreadyAdded(varName, operation)) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public final class StringUtil {
public static final String OPEN_BRACE = "{";
public static final String CLOSE_BRACE = "}";
public static final String SLASH = "/";
public static final char SLASH_CHAR = '/';
public static final String DOLLAR = "$";
public static final String DOT = ".";
public static final String COMMA = ",";
Expand Down
45 changes: 26 additions & 19 deletions openapi/src/main/java/io/micronaut/openapi/visitor/UrlUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import java.util.List;

import static io.micronaut.openapi.visitor.StringUtil.CLOSE_BRACE;
import static io.micronaut.openapi.visitor.StringUtil.DOLLAR;
import static io.micronaut.openapi.visitor.StringUtil.OPEN_BRACE;
import static io.micronaut.openapi.visitor.StringUtil.SLASH;
import static io.micronaut.openapi.visitor.StringUtil.SLASH_CHAR;

/**
* URL and URL paths util methods.
Expand All @@ -48,10 +50,14 @@ public static List<String> buildUrls(List<Segment> segments) {
var resultStrings = new ArrayList<String>();
for (var res : results) {
var url = res.toString();
if (url.endsWith(SLASH) && url.length() > 1) {
url = url.substring(0, url.length() - SLASH.length());
} else if (!url.startsWith(SLASH) && !url.startsWith(DOLLAR)) {
url = SLASH + url;
} else if (url.startsWith(SLASH + DOLLAR)) {
url = url.substring(1);
}
if (!resultStrings.contains(url)) {
if (url.endsWith(SLASH)) {
url = url.substring(0, url.length() - SLASH.length());
}
resultStrings.add(url);
}
}
Expand All @@ -67,22 +73,20 @@ private static void appendSegment(Segment segment, Segment prevSegment, List<Str
results.add(new StringBuilder(value));
return;
}
var builder = new StringBuilder(SLASH).append(value);
if (!value.endsWith(SLASH)) {
builder.append(SLASH);
}
var builder = new StringBuilder();
builder.append(value);
results.add(builder);
if (type == SegmentType.OPT_VAR) {
results.add(new StringBuilder(SLASH));
results.add(new StringBuilder());
}
return;
}
if (type == SegmentType.CONST || type == SegmentType.REQ_VAR || type == SegmentType.PLACEHOLDER) {
for (var result : results) {
result.append(value);
if (type != SegmentType.PLACEHOLDER) {
result.append(SLASH);
}
// if (type != SegmentType.PLACEHOLDER) {
// result.append(SLASH);
// }
}
return;
}
Expand All @@ -92,10 +96,10 @@ private static void appendSegment(Segment segment, Segment prevSegment, List<Str
newResults.add(new StringBuilder(result));
}
for (var result : results) {
if (prevSegment.type == SegmentType.OPT_VAR && result.indexOf(prevSegment.value + SLASH) < 0) {
if (prevSegment.type == SegmentType.OPT_VAR && result.indexOf(prevSegment.value) < 0) {
continue;
}
result.append(value).append(SLASH);
result.append(SLASH_CHAR).append(value);
}
results.addAll(newResults);
}
Expand Down Expand Up @@ -128,6 +132,9 @@ public static List<Segment> parsePathSegments(String pathString) {

// process placeholders
if (varStartPos >= 1 && pathString.charAt(varStartPos - 1) == '$') {
if (!constSegment.isEmpty()) {
addConstValue(constSegment.substring(0, constSegment.length() - 1), segments);
}
segments.add(new Segment(SegmentType.PLACEHOLDER, pathString.substring(varStartPos - 1, varEndPos + 1)));
startPos = varEndPos + 1;
continue;
Expand Down Expand Up @@ -166,12 +173,12 @@ public static List<Segment> parsePathSegments(String pathString) {
}

private static void addConstValue(String constValue, List<Segment> segments) {
if (constValue.startsWith(SLASH)) {
constValue = constValue.substring(1);
}
if (constValue.endsWith(SLASH)) {
constValue = constValue.substring(0, constValue.length() - SLASH.length());
}
// if (constValue.startsWith(SLASH)) {
// constValue = constValue.substring(1);
// }
// if (constValue.endsWith(SLASH)) {
// constValue = constValue.substring(0, constValue.length() - SLASH.length());
// }
if (!constValue.isEmpty()) {
segments.add(new Segment(SegmentType.CONST, constValue));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,82 @@ class MyBean {}
pathItem3.get.parameters[3].in == 'query'
}

void "test parse URL with :"() {

given: "An API definition"
when:
buildBeanDefinition('test.MyBean', '''
package test;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;import io.micronaut.http.annotation.PathVariable;
@Controller("/")
interface Test {
@Get("/hello/{pathVar2}${placeholder}/tete:test4")
String test1(@PathVariable String pathVar2);
@Get("/hello/{pathVar2}:test2/${placeholder}:test4")
String test2(@PathVariable String pathVar2);
@Get("/hello{/optVar1}:test5/{pathVar1}:test/{pathVar2}:test2/${placeholder}:test4/const:test3")
String test3(@PathVariable String pathVar1);
}
class Greeting {
public String message;
}
@jakarta.inject.Singleton
class MyBean {}
''')
then: "the state is correct"
Utils.testReference != null

when: "The OpenAPI is retrieved"
OpenAPI openAPI = Utils.testReference

def pathItem1 = openAPI.paths.get("/hello/{pathVar2}\${placeholder}/tete:test4")
def pathItem2 = openAPI.paths.get("/hello/{pathVar2}:test2/\${placeholder}:test4")
def pathItem3 = openAPI.paths.get("/hello/{optVar1}:test5/{pathVar1}:test/{pathVar2}:test2/\${placeholder}:test4/const:test3")
def pathItem4 = openAPI.paths.get("/hello:test5/{pathVar1}:test/{pathVar2}:test2/\${placeholder}:test4/const:test3")

then:
pathItem1.get.parameters
pathItem1.get.parameters.size() == 1
pathItem1.get.parameters[0].name == 'pathVar2'
pathItem1.get.parameters[0].required
pathItem1.get.parameters[0].in == 'path'

pathItem2.get.parameters
pathItem2.get.parameters.size() == 1
pathItem2.get.parameters[0].name == 'pathVar2'
pathItem2.get.parameters[0].required
pathItem2.get.parameters[0].in == 'path'

pathItem3.get.parameters
pathItem3.get.parameters.size() == 3
pathItem3.get.parameters[0].name == 'pathVar1'
pathItem3.get.parameters[0].required
pathItem3.get.parameters[0].in == 'path'
pathItem3.get.parameters[1].name == 'optVar1'
pathItem3.get.parameters[1].required
pathItem3.get.parameters[1].in == 'path'
pathItem3.get.parameters[2].name == 'pathVar2'
pathItem3.get.parameters[2].required
pathItem3.get.parameters[2].in == 'path'

pathItem4.get.parameters
pathItem4.get.parameters.size() == 2
pathItem4.get.parameters[0].name == 'pathVar1'
pathItem4.get.parameters[0].required
pathItem4.get.parameters[0].in == 'path'
pathItem4.get.parameters[1].name == 'pathVar2'
pathItem4.get.parameters[1].required
pathItem4.get.parameters[1].in == 'path'
}

void "test @Parameter in header and explode is true"() {

given: "An API definition"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.micronaut.openapi.visitor

import io.micronaut.openapi.AbstractOpenApiTypeElementSpec
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.Operation

class OpenApiPathParamRegexSpec extends AbstractOpenApiTypeElementSpec {

Expand All @@ -20,7 +19,7 @@ import io.swagger.v3.oas.annotations.Operation;
class OpenApiController {
@Operation(summary = "Update tag", description = "Updates an existing tag", tags = "users_tag")
@Post("/tags/{tagId: \\\\d+}/{path:.*}{.ext}/update/{?max,offset}{/id:[a-zA-Z]+}")
@Post("/tags/{tagId: \\\\d+}/{path:.*}{.ext}/update{?max,offset}{/id:[a-zA-Z]+}")
public void postRaw() {
}
}
Expand Down

0 comments on commit ea81b0f

Please sign in to comment.