Skip to content

Commit fca143e

Browse files
committed
Optimized path parameter maps to save allocating it if not necessary
1 parent de06d19 commit fca143e

File tree

8 files changed

+63
-48
lines changed

8 files changed

+63
-48
lines changed

vertx-web-api-contract/src/main/java/io/vertx/ext/web/api/validation/impl/BaseValidationHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private Map<String, RequestParameter> validatePathParams(RoutingContext routingC
104104

105105
for (ParameterValidationRule rule : pathParamsRules.values()) {
106106
String name = rule.getName();
107-
if (routingContext.hasPathParam(name)) {
107+
if (name != null) {
108108
String pathParam = routingContext.pathParam(name);
109109
if (pathParam != null || !rule.isOptional() ) {
110110
RequestParameter parsedParam = rule.validateSingleParam(pathParam);

vertx-web-validation/src/main/java/io/vertx/ext/web/validation/impl/ValidationHandlerImpl.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,12 @@ private void runPredicates(RoutingContext context) throws BadRequestException {
187187

188188
private Future<Map<String, RequestParameter>> validatePathParams(RoutingContext routingContext) {
189189
// Validation process validate only params that are registered in the validation -> extra params are allowed
190-
Map<String, List<String>> pathParams = new HashMap<>();
191-
routingContext.forEachPathParam((name, params) -> pathParams.put(name, Collections.singletonList(params)));
190+
Map<String, List<String>> pathParams = routingContext
191+
.pathParams()
192+
.entrySet()
193+
.stream()
194+
.map(e -> new SimpleImmutableEntry<>(e.getKey(), Collections.singletonList(e.getValue())))
195+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
192196

193197
Map<String, RequestParameter> parsedParams = new HashMap<>();
194198

vertx-web/src/main/java/io/vertx/ext/web/RoutingContext.java

+6-13
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.time.Instant;
3535
import java.util.List;
3636
import java.util.Map;
37-
import java.util.function.BiConsumer;
3837

3938
import static io.vertx.codegen.annotations.GenIgnore.PERMITTED_TYPE;
4039

@@ -614,11 +613,10 @@ default LanguageHeader preferredLanguage() {
614613
}
615614

616615
/**
617-
* Returns a map of named parameters as defined in path declaration with their actual values
618-
*
619-
* @return the map of named parameters
616+
* Add a new one or replace an existing path parameter
617+
* @throws NullPointerException when the name or value is null
620618
*/
621-
Map<String, String> pathParams();
619+
void addOrReplacePathParam(String name, String value);
622620

623621
/**
624622
* Remove a path parameter
@@ -627,16 +625,11 @@ default LanguageHeader preferredLanguage() {
627625
boolean removePathParam(String s);
628626

629627
/**
630-
* Iterate over all the path parameters
628+
* Returns an unmodifiable map of named parameters as defined in path declaration with their actual values
631629
*
632-
* @param pathParamsConsumer the consumer for each path parameter
633-
*/
634-
void forEachPathParam(BiConsumer<String, String> pathParamsConsumer);
635-
636-
/**
637-
* @return {@code true} if the context has a path parameter with the specified {@code name}, {@code false} otherwise.
630+
* @return the map of named parameters
638631
*/
639-
boolean hasPathParam(String name);
632+
Map<String, String> pathParams();
640633

641634
/**
642635
* Gets the value of a single path parameter

vertx-web/src/main/java/io/vertx/ext/web/impl/RouteState.java

+6-9
Original file line numberDiff line numberDiff line change
@@ -1030,8 +1030,7 @@ public int matches(RoutingContextImplBase context, String mountPoint, boolean fa
10301030
if (!exactPath) {
10311031
context.matchRest = m.start("rest");
10321032
// always replace
1033-
context.pathParams()
1034-
.put("*", path.substring(context.matchRest));
1033+
context.addOrReplacePathParam("*", path.substring(context.matchRest));
10351034
}
10361035

10371036
if (!isEmpty(groups)) {
@@ -1162,8 +1161,7 @@ private boolean pathMatches(String mountPoint, RoutingContext ctx) {
11621161

11631162
if (exactPath) {
11641163
// exact path has no "rest"
1165-
ctx.pathParams()
1166-
.remove("*");
1164+
ctx.removePathParam("*");
11671165

11681166
return pathMatchesExact(thePath, requestPath, pathEndsWithSlash);
11691167
} else {
@@ -1184,17 +1182,16 @@ private boolean pathMatches(String mountPoint, RoutingContext ctx) {
11841182
// because the mount path ended with a wildcard we are relaxed in the check
11851183
if (thePath.regionMatches(0, requestPath, 0, pathLen - 1)) {
11861184
// handle the "rest" as path param *, always known to be empty
1187-
ctx.pathParams()
1188-
.put("*", "/");
1185+
ctx.addOrReplacePathParam("*", "/");
11891186
return true;
11901187
}
11911188
}
11921189
}
11931190

11941191
if (requestPath.startsWith(thePath)) {
11951192
// handle the "rest" as path param *
1196-
ctx.pathParams()
1197-
.put("*", URIDecoder.decodeURIComponent(requestPath.substring(thePath.length()), false));
1193+
ctx.addOrReplacePathParam("*",
1194+
URIDecoder.decodeURIComponent(requestPath.substring(thePath.length()), false));
11981195
return true;
11991196
}
12001197
return false;
@@ -1267,7 +1264,7 @@ private void addPathParam(RoutingContext context, String name, String value) {
12671264
if (!request.params().contains(name)) {
12681265
request.params().add(name, decodedValue);
12691266
}
1270-
context.pathParams().put(name, decodedValue);
1267+
context.addOrReplacePathParam(name, decodedValue);
12711268
}
12721269

12731270
boolean hasNextContextHandler(RoutingContextImplBase context) {

vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextDecorator.java

+10
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,16 @@ public void reroute(HttpMethod method, String path) {
254254
decoratedContext.reroute(method, path);
255255
}
256256

257+
@Override
258+
public void addOrReplacePathParam(String name, String value) {
259+
decoratedContext.addOrReplacePathParam(name, value);
260+
}
261+
262+
@Override
263+
public boolean removePathParam(String s) {
264+
return decoratedContext.removePathParam(s);
265+
}
266+
257267
@Override
258268
public Map<String, String> pathParams() {
259269
return decoratedContext.pathParams();

vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java

+26-13
Original file line numberDiff line numberDiff line change
@@ -441,28 +441,40 @@ public void reroute(HttpMethod method, String path) {
441441
}
442442

443443
@Override
444-
public void forEachPathParam(final BiConsumer<String, String> pathParamsConsumer) {
445-
if (pathParams != null) {
446-
pathParams.forEach(pathParamsConsumer);
447-
}
444+
public void addOrReplacePathParam(final String name, final String value) {
445+
Objects.requireNonNull(name, "name");
446+
Objects.requireNonNull(value, "value");
447+
getOrCreatePathParams().put(name, value);
448448
}
449449

450450
@Override
451-
public boolean hasPathParam(final String name) {
452-
if (pathParams != null) {
453-
return pathParams.containsKey(name);
451+
public Map<String, String> pathParams() {
452+
if (pathParams == null || pathParams.isEmpty()) {
453+
return Collections.emptyMap();
454454
}
455-
return false;
455+
return Collections.unmodifiableMap(pathParams);
456456
}
457457

458458
@Override
459-
public Map<String, String> pathParams() {
460-
return getPathParams();
459+
public boolean removePathParam(String s) {
460+
if (s == null) {
461+
return false;
462+
}
463+
if (pathParams != null) {
464+
return pathParams.remove(s) != null;
465+
}
466+
return false;
461467
}
462468

463469
@Override
464470
public @Nullable String pathParam(String name) {
465-
return getPathParams().get(name);
471+
if (name == null) {
472+
return null;
473+
}
474+
if (pathParams != null) {
475+
return pathParams.get(name);
476+
}
477+
return null;
466478
}
467479

468480
@Override
@@ -506,9 +518,10 @@ private MultiMap getQueryParams(Charset charset) {
506518
return queryParams;
507519
}
508520

509-
private Map<String, String> getPathParams() {
521+
private Map<String, String> getOrCreatePathParams() {
510522
if (pathParams == null) {
511-
pathParams = new HashMap<>();
523+
// let's start small
524+
pathParams = new HashMap<>(1);
512525
}
513526
return pathParams;
514527
}

vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -310,18 +310,18 @@ public void reroute(HttpMethod method, String path) {
310310
}
311311

312312
@Override
313-
public Map<String, String> pathParams() {
314-
return inner.pathParams();
313+
public void addOrReplacePathParam(final String name, final String value) {
314+
inner.addOrReplacePathParam(name, value);
315315
}
316316

317317
@Override
318-
public boolean hasPathParam(final String name) {
319-
return inner.hasPathParam(name);
318+
public boolean removePathParam(final String s) {
319+
return inner.removePathParam(s);
320320
}
321321

322322
@Override
323-
public void forEachPathParam(final BiConsumer<String, String> pathParamsConsumer) {
324-
inner.forEachPathParam(pathParamsConsumer);
323+
public Map<String, String> pathParams() {
324+
return inner.pathParams();
325325
}
326326

327327
@Override

vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -863,8 +863,7 @@ public void testPercentEncoding() throws Exception {
863863
@Test
864864
public void testPathParamsAreFulfilled() throws Exception {
865865
router.route("/blah/:abc/quux/:def/eep/:ghi").handler(rc -> {
866-
Map<String, String> params = rc.pathParams();
867-
rc.response().setStatusMessage(params.get("abc") + params.get("def") + params.get("ghi")).end();
866+
rc.response().setStatusMessage(rc.pathParam("abc") + rc.pathParam("def") + rc.pathParam("ghi")).end();
868867
});
869868
testPattern("/blah/tim/quux/julien/eep/nick", "timjuliennick");
870869
}
@@ -877,11 +876,10 @@ public void testPathParamsDoesNotOverrideQueryParam() throws Exception {
877876
final String queryParamValue2 = "queryParamValue2";
878877
final String sep = ",";
879878
router.route("/blah/:" + paramName + "/test").handler(rc -> {
880-
Map<String, String> params = rc.pathParams();
881879
MultiMap queryParams = rc.request().params();
882880
List<String> values = queryParams.getAll(paramName);
883881
String qValue = values.stream().collect(Collectors.joining(sep));
884-
rc.response().setStatusMessage(params.get(paramName) + "|" + qValue).end();
882+
rc.response().setStatusMessage(rc.pathParam(paramName) + "|" + qValue).end();
885883
});
886884
testRequest(HttpMethod.GET,
887885
"/blah/" + pathParamValue + "/test?" + paramName + "=" + queryParamValue1 + "&" + paramName + "=" + queryParamValue2,

0 commit comments

Comments
 (0)