From 88ef3ec0cc1870c23373ee7b12453be9d3dbe58a Mon Sep 17 00:00:00 2001 From: Auri Munoz Date: Fri, 20 Dec 2024 15:54:19 +0100 Subject: [PATCH] Support for populating Map and MultiValueMap with request parameters in @RequestParam --- .../runtime/ServletRequestContext.java | 12 +++ .../simple/MapWithParamConverterTest.java | 26 ++++- .../deployment/MapParamConverter.java | 32 +++++++ .../deployment/MapParamConverterProvider.java | 20 ++++ .../requestparam/RequestParamController.java | 60 ++++++++++++ .../RequestParamControllerTest.java | 94 +++++++++++++++++++ .../common/processor/EndpointIndexer.java | 13 +++ .../processor/ServerEndpointIndexer.java | 9 ++ .../core/ResteasyReactiveRequestContext.java | 46 +++++---- .../parameters/converters/MapConverter.java | 76 +++++++++++++++ .../server/spi/ServerHttpRequest.java | 2 + .../VertxResteasyReactiveRequestContext.java | 13 +++ 12 files changed, 380 insertions(+), 23 deletions(-) create mode 100644 extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverter.java create mode 100644 extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverterProvider.java create mode 100644 extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamController.java create mode 100644 extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamControllerTest.java create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/MapConverter.java diff --git a/extensions/resteasy-reactive/rest-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java b/extensions/resteasy-reactive/rest-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java index 369ae603e4610..66c5450390b50 100644 --- a/extensions/resteasy-reactive/rest-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java +++ b/extensions/resteasy-reactive/rest-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java @@ -9,6 +9,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -262,6 +263,17 @@ public List getAllQueryParams(String name) { return context.queryParam(name); } + @Override + public Map getQueryParams() { + MultiMap entries = context.queryParams(); + Map queryParams = new HashMap<>(entries.size()); + if (!entries.isEmpty()) { + entries.entries().stream() + .map(stringStringEntry -> queryParams.put(stringStringEntry.getKey(), stringStringEntry.getValue())); + } + return queryParams; + } + @Override public String query() { return request.getQueryString(); diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/MapWithParamConverterTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/MapWithParamConverterTest.java index 419dfdd721533..cf2637e993ad3 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/MapWithParamConverterTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/MapWithParamConverterTest.java @@ -2,6 +2,8 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -22,6 +24,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -87,17 +90,32 @@ public MapParamConverter(Class rawType, Type genericType) { this.rawType = rawType; } - @Override public T fromString(String value) { if (rawType.isAssignableFrom(String.class)) { //noinspection unchecked return (T) value; } try { - return genericType != null ? objectMapper.readValue(value, genericType) - : objectMapper.readValue(value, rawType); + JsonNode jsonNode = objectMapper.readTree(value); + if (jsonNode.isArray()) { + // Process as a list of maps and merge them into a single map + JavaType listType = objectMapper.getTypeFactory() + .constructCollectionType(List.class, rawType); + List> list = objectMapper.readValue(value, listType); + + Map mergedMap = new LinkedHashMap<>(); + for (Map map : list) { + mergedMap.putAll(map); + } + return (T) mergedMap; + } else { + // single object + return genericType != null + ? objectMapper.readValue(value, genericType) + : objectMapper.readValue(value, rawType); + } } catch (JsonProcessingException e) { - throw (new RuntimeException(e)); + throw new RuntimeException(e); } } diff --git a/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverter.java b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverter.java new file mode 100644 index 0000000000000..df0b840d56fc9 --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverter.java @@ -0,0 +1,32 @@ +package io.quarkus.spring.web.resteasy.reactive.deployment; + +import java.util.HashMap; +import java.util.Map; + +import jakarta.ws.rs.ext.ParamConverter; + +public class MapParamConverter implements ParamConverter> { + + @Override + public Map fromString(String value) { + // Parse params to a Map + Map map = new HashMap<>(); + if (value != null && !value.isEmpty()) { + String[] pairs = value.split("&"); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + map.put(keyValue[0], keyValue[1]); + } + } + } + return map; + } + + @Override + public String toString(Map value) { + StringBuilder sb = new StringBuilder(); + value.forEach((key, val) -> sb.append(key).append("=").append(val).append("&")); + return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : ""; + } +} diff --git a/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverterProvider.java b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverterProvider.java new file mode 100644 index 0000000000000..5b4cce14a5a03 --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/resteasy/reactive/deployment/MapParamConverterProvider.java @@ -0,0 +1,20 @@ +package io.quarkus.spring.web.resteasy.reactive.deployment; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Map; + +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class MapParamConverterProvider implements ParamConverterProvider { + @Override + public ParamConverter getConverter(Class rawType, Type genericType, Annotation[] annotations) { + if (rawType == Map.class) { + return (ParamConverter) new MapParamConverter(); + } + return null; + } +} diff --git a/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamController.java b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamController.java new file mode 100644 index 0000000000000..ae2f5917f0543 --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamController.java @@ -0,0 +1,60 @@ +package io.quarkus.spring.web.requestparam; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping +public class RequestParamController { + + @GetMapping("/api/foos") + @ResponseBody + public String getFoos(@RequestParam String id) { + return "ID: " + id; + } + + @PostMapping("/api/foos") + @ResponseBody + public String addFoo(@RequestParam(name = "id") String fooId, @RequestParam String name) { + return "ID: " + fooId + " Name: " + name; + } + + @GetMapping("/api/foos/notParamRequired") + @ResponseBody + public String getFoosNotParamRequired2(@RequestParam(required = false) String id) { + return "ID: " + id; + } + + @GetMapping("/api/foos/optional") + @ResponseBody + public String getFoosOptional(@RequestParam Optional id) { + return "ID: " + id.orElseGet(() -> "not provided"); + } + + @GetMapping("/api/foos/defaultValue") + @ResponseBody + public String getFoosDefaultValue(@RequestParam(defaultValue = "test") String id) { + return "ID: " + id; + } + + @PostMapping("/api/foos/map") + @ResponseBody + public String updateFoos(@RequestParam Map allParams) { + return "Parameters are " + allParams.entrySet(); + } + + @GetMapping("/api/foos/multivalue") + @ResponseBody + public String getFoosMultiValue(@RequestParam List id) { + return "IDs are " + id; + } + +} diff --git a/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamControllerTest.java b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamControllerTest.java new file mode 100644 index 0000000000000..bfb50e28461e2 --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/requestparam/RequestParamControllerTest.java @@ -0,0 +1,94 @@ +package io.quarkus.spring.web.requestparam; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class RequestParamControllerTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RequestParamController.class)); + + @Test + public void whenInvokeGetQueryStringThenTheOriginQueryStringIsReturned() throws Exception { + when().get("/api/foos?id=abc") + .then() + .statusCode(200) + .body(is("ID: abc")); + + // should return 400 because, in Spring, method parameters annotated with @RequestParam are required by default. + // see SpringWebResteasyReactiveProcessor L298 + when().get("/api/foos") + .then() + .statusCode(200); + } + + @Test + public void whenConfigureParamToBeOptionalThenTheGetQueryWorksWithAndWithoutRequestParam() throws Exception { + when().get("/api/foos/notParamRequired?id=abc") + .then() + .statusCode(200) + .body(is("ID: abc")); + + when().get("/api/foos/notParamRequired") + .then() + .statusCode(200) + .body(is("ID: null")); + } + + @Test + public void whenWrapingParamInOptionalThenTheGetQueryWorksWithAndWithoutRequestParam() throws Exception { + when().get("/api/foos/optional?id=abc") + .then() + .statusCode(200) + .body(is("ID: abc")); + + when().get("/api/foos/optional") + .then() + .statusCode(200) + .body(is("ID: not provided")); + } + + @Test + public void whenDefaultValueProvidedThenItIsReturnedIfRequestParamIsAbsent() throws Exception { + when().get("/api/foos/defaultValue?id=abc") + .then() + .statusCode(200) + .body(is("ID: abc")); + + when().get("/api/foos/defaultValue") + .then() + .statusCode(200) + .body(is("ID: test")); + } + + @Test + public void whenInvokePostQueryWithSpecificParamNameThenTheOriginQueryStringIsReturned() throws Exception { + when().post("/api/foos/map?id=abc&name=bar") + .then() + .statusCode(200) + .body(containsString("Parameters are [name=bar, id=abc]")); + + } + + @Test + public void testMultivalue() throws Exception { + when().get("/api/foos/multivalue?id=1,2,3") + .then() + .statusCode(200) + .body(containsString("IDs are [1,2,3]")); + + when().get("/api/foos/multivalue?id=1&id=2") + .then() + .statusCode(200).log().body() + .body(containsString("IDs are [1, 2]")); + } + +} diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index c9e4a537b2139..18501c55b298d 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -31,6 +31,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LOCAL_DATE_TIME; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LOCAL_TIME; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LONG; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MAP; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MATRIX_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MULTI; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MULTI_PART_DATA_INPUT; @@ -1374,6 +1375,14 @@ && isParameterContainerType(paramType.asClassType())) { handleSortedSetParam(existingConverters, errorLocation, hasRuntimeConverters, builder, elementType, currentMethodInfo); } + } else if (pt.name().equals(MAP)) { + typeHandled = true; + builder.setSingle(false); + elementType = toClassName(pt.arguments().get(0), currentClassInfo, actualEndpointInfo, index); + if (convertible) { + handleMapParam(existingConverters, errorLocation, hasRuntimeConverters, builder, elementType, + currentMethodInfo); + } } else if (pt.name().equals(OPTIONAL)) { typeHandled = true; elementType = toClassName(pt.arguments().get(0), currentClassInfo, actualEndpointInfo, index); @@ -1534,6 +1543,10 @@ protected void handleSetParam(Map existingConverters, String err PARAM builder, String elementType, MethodInfo currentMethodInfo) { } + protected void handleMapParam(Map existingConverters, String errorLocation, boolean hasRuntimeConverters, + PARAM builder, String elementType, MethodInfo currentMethodInfo) { + } + protected void handleListParam(Map existingConverters, String errorLocation, boolean hasRuntimeConverters, PARAM builder, String elementType, MethodInfo currentMethodInfo) { } diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java index 7ba93d0418f01..7c92be582d4c0 100644 --- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java +++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java @@ -74,6 +74,7 @@ import org.jboss.resteasy.reactive.server.core.parameters.converters.LocalDateParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.LocalDateTimeParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.LocalTimeParamConverter; +import org.jboss.resteasy.reactive.server.core.parameters.converters.MapConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.NoopParameterConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.OffsetDateTimeParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.OffsetTimeParamConverter; @@ -532,6 +533,14 @@ protected void handleSetParam(Map existingConverters, String err builder.setConverter(new SetConverter.SetSupplier(converter)); } + @Override + protected void handleMapParam(Map existingConverters, String errorLocation, boolean hasRuntimeConverters, + ServerIndexedParameter builder, String elementType, MethodInfo currentMethodInfo) { + ParameterConverterSupplier converter = extractConverter(elementType, index, + existingConverters, errorLocation, hasRuntimeConverters, builder.getAnns(), currentMethodInfo); + builder.setConverter(new MapConverter.MapSupplier(converter)); + } + @Override protected void handleListParam(Map existingConverters, String errorLocation, boolean hasRuntimeConverters, ServerIndexedParameter builder, String elementType, MethodInfo currentMethodInfo) { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java index e72ad3b6913df..8cd5473b1d9cc 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java @@ -14,6 +14,7 @@ import java.util.Deque; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; import java.util.regex.Matcher; @@ -870,29 +871,36 @@ public Object getQueryParameter(String name, boolean single, boolean encoded, St } return val; } - - // empty collections must not be turned to null - List strings = serverRequest().getAllQueryParams(name).stream() - .filter(p -> !p.isEmpty()) - .toList(); - if (encoded) { - List newStrings = new ArrayList<>(); - for (String i : strings) { - newStrings.add(Encode.encodeQueryParam(i)); + List allQueryParams = serverRequest().getAllQueryParams(name); + if (allQueryParams != null && !allQueryParams.isEmpty()) { + // empty collections must not be turned to null + List strings = allQueryParams.stream() + .filter(p -> !p.isEmpty()) + .toList(); + if (encoded) { + List newStrings = new ArrayList<>(); + for (String i : strings) { + newStrings.add(Encode.encodeQueryParam(i)); + } + strings = newStrings; } - strings = newStrings; - } - if (separator != null) { - List result = new ArrayList<>(strings.size()); - for (int i = 0; i < strings.size(); i++) { - String[] parts = strings.get(i).split(separator); - result.addAll(Arrays.asList(parts)); + if (separator != null) { + List result = new ArrayList<>(strings.size()); + for (int i = 0; i < strings.size(); i++) { + String[] parts = strings.get(i).split(separator); + result.addAll(Arrays.asList(parts)); + } + return result; + } else { + return strings; } - return result; - } else { - return strings; } + Map queryParams = serverRequest().getQueryParams(); + if (queryParams != null && !queryParams.isEmpty()) { + return queryParams; + } + return Collections.EMPTY_LIST; } @Override diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/MapConverter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/MapConverter.java new file mode 100644 index 0000000000000..896a7e89b1221 --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/MapConverter.java @@ -0,0 +1,76 @@ +package org.jboss.resteasy.reactive.server.core.parameters.converters; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.jboss.resteasy.reactive.server.model.ParamConverterProviders; + +public class MapConverter implements ParameterConverter { + + private final ParameterConverter delegate; + + public MapConverter(ParameterConverter delegate) { + this.delegate = delegate; + } + + @Override + public Object convert(Object parameter) { + if (parameter instanceof Map) { + Map result = new HashMap<>(); + Map input = (Map) parameter; + for (String key : input.keySet()) { + result.put(key, input.get(key)); + } + return result; + } + if (parameter == null) { + return Collections.emptyMap(); + } else { + return Collections.emptyMap(); + } + } + + @Override + public void init(ParamConverterProviders deployment, Class rawType, Type genericType, Annotation[] annotations) { + delegate.init(deployment, rawType, genericType, annotations); + } + + @Override + public boolean isForSingleObjectContainer() { + return true; + } + + public static class MapSupplier implements DelegatingParameterConverterSupplier { + private ParameterConverterSupplier delegate; + + public MapSupplier() { + } + + // invoked by reflection for BeanParam in ClassInjectorTransformer + public MapSupplier(ParameterConverterSupplier delegate) { + this.delegate = delegate; + } + + @Override + public String getClassName() { + return MapConverter.class.getName(); + } + + @Override + public ParameterConverter get() { + return delegate == null ? new MapConverter(null) : new MapConverter(delegate.get()); + } + + public ParameterConverterSupplier getDelegate() { + return delegate; + } + + public MapSupplier setDelegate(ParameterConverterSupplier delegate) { + this.delegate = delegate; + return this; + } + } +} diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerHttpRequest.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerHttpRequest.java index 53c2d6ea0c05a..fefe5773f47a3 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerHttpRequest.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerHttpRequest.java @@ -34,6 +34,8 @@ public interface ServerHttpRequest { String getQueryParam(String name); + Map getQueryParams(); + List getAllQueryParams(String name); String query(); diff --git a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java index 51e1c8d9605f8..f5d839fedbde8 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java @@ -6,6 +6,7 @@ import java.nio.ByteBuffer; import java.nio.file.Paths; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -215,6 +216,18 @@ public List getAllQueryParams(String name) { return context.queryParam(name); } + @Override + public Map getQueryParams() { + MultiMap entries = context.queryParams(); + Map queryParams = new HashMap<>(entries.size()); + if (!entries.isEmpty()) { + for (Map.Entry entry : entries.entries()) { + queryParams.put(entry.getKey(), entry.getValue()); + } + } + return queryParams; + } + @Override public String query() { return request.query();