Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@

import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RequestParam;

Expand Down Expand Up @@ -54,18 +55,41 @@
*/
public class RequestParamArgumentResolver extends AbstractNamedValueArgumentResolver {

private boolean formatAsSingleValue = true;


public RequestParamArgumentResolver(ConversionService conversionService) {
super(conversionService);
}

public RequestParamArgumentResolver(ConversionService conversionService, boolean formatAsSingleValue) {
super(conversionService);
this.formatAsSingleValue = formatAsSingleValue;
}


@Override
@Nullable
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter, HttpRequestValues.Metadata requestValues) {
MediaType contentType = requestValues.getContentType();
if (contentType != null && isMultiValueFormContentType(contentType)) {
this.formatAsSingleValue = true;
}

return createNamedValueInfo(parameter);
}

@Override
@Nullable
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
RequestParam annot = parameter.getParameterAnnotation(RequestParam.class);
if (annot == null) {
return null;
}

return (annot == null ? null :
new NamedValueInfo(annot.name(), annot.required(), annot.defaultValue(), "request parameter", true));
new NamedValueInfo(annot.name(), annot.required(), annot.defaultValue(),
"request parameter", this.formatAsSingleValue));
}

@Override
Expand All @@ -75,4 +99,17 @@ protected void addRequestValue(
requestValues.addRequestParameter(name, (String) value);
}

protected boolean isFormatAsSingleValue() {
return this.formatAsSingleValue;
}

protected void setFormatAsSingleValue(boolean formatAsSingleValue) {
this.formatAsSingleValue = formatAsSingleValue;
}

protected boolean isMultiValueFormContentType(MediaType contentType) {
return contentType.equals(MediaType.APPLICATION_FORM_URLENCODED)
|| contentType.getType().equals("multipart");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package org.springframework.web.service.invoker;

import java.util.HashMap;
import java.util.List;

import org.junit.jupiter.api.Test;

import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.PostExchange;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -41,14 +45,14 @@ class RequestParamArgumentResolverTests {

private final TestExchangeAdapter client = new TestExchangeAdapter();

private final Service service =
HttpServiceProxyFactory.builderFor(this.client).build().createClient(Service.class);
private final HttpServiceProxyFactory.Builder builder = HttpServiceProxyFactory.builderFor(this.client);


@Test
@SuppressWarnings("unchecked")
void requestParam() {
this.service.postForm("value 1", "value 2");
Service service = builder.build().createClient(Service.class);
service.postForm("value 1", "value 2");

Object body = this.client.getRequestValues().getBodyValue();
assertThat(body).isInstanceOf(MultiValueMap.class);
Expand All @@ -57,12 +61,34 @@ void requestParam() {
.containsEntry("param2", List.of("value 2"));
}

@Test
@SuppressWarnings("unchecked")
void requestParamWithDisabledFormattingCollectionValue() {
ConversionService conversionService = new DefaultConversionService();
boolean formatAsSingleValue = false;
Service service = builder.customArgumentResolver(
new RequestParamArgumentResolver(conversionService, formatAsSingleValue))
.build()
.createClient(Service.class);
List<String> collectionParams = List.of("1", "2", "3");
service.getForm("value 1", collectionParams);

Object uriVariables = this.client.getRequestValues().getUriVariables();
assertThat(uriVariables).isNotInstanceOf(MultiValueMap.class).isInstanceOf(HashMap.class);
assertThat((HashMap<String, String>) uriVariables).hasSize(4)
.containsEntry("queryParam0", "param1")
.containsEntry("queryParam0[0]", "value 1")
.containsEntry("queryParam1", "param2")
.containsEntry("queryParam1[0]", String.join(",", collectionParams));
}

private interface Service {

@PostExchange(contentType = "application/x-www-form-urlencoded")
void postForm(@RequestParam String param1, @RequestParam String param2);

@GetExchange
void getForm(@RequestParam String param1, @RequestParam List<String> param2);
}

}