Affects: 2.4.0-SNAPSHOT Affects: Spring boot 2.3.4.RELEASE
Same behavior with kotlin version 1.3.72 and 1.4.10 Tested with java 8
I try to map a GET request into a pojo class in kotlin. The method param resolver fail to map properly the query params.
I used to have no problem to do this mapping in Java; I am not sure anymore but I think it was working before for Kotlin with Set/List/etc. Now it does not work anymore.
I don't think I have to implement my own HandlerMethodArgumentResolver for all my custom criterias, I use only basic fields, and java works but not kotlin.
I know about StringToCollectionConverter, DelimitedStringToCollectionConverter and etc but it does not seem to be working with Kotlin Data class (or normal class)
Do a get with:
localhost:8080/test/param/test-1?projectIdIn2=1,2,3&projectIdIn3=1,2,4&projectIdIn4=1,2,5&projectIdIn5=1,2,6&projectIdIn6=1,2,7&projectIdIn8=1,2,9&projectIdIn1=1&projectIdIn1=3
Fail with
2020-09-25 15:36:19.865 WARN 10780 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.ModelAttributeMethodProcessor$1: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'simpleCriteria' on field 'projectIdIn3': rejected value [1,2,4]; codes [typeMismatch.simpleCriteria.projectIdIn3,typeMismatch.projectIdIn3,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [simpleCriteria.projectIdIn3,projectIdIn3]; arguments []; default message [projectIdIn3]]; default message [Failed to convert value of type 'java.lang.String[]' to required type 'java.util.Set'; nested exception is java.lang.NumberFormatException: For input string: "1,2,4"]
Field error in object 'simpleCriteria' on field 'projectIdIn5': rejected value [1,2,6]; codes [typeMismatch.simpleCriteria.projectIdIn5,typeMismatch.projectIdIn5,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [simpleCriteria.projectIdIn5,projectIdIn5]; arguments []; default message [projectIdIn5]]; default message [Failed to convert value of type 'java.lang.String[]' to required type 'java.util.List'; nested exception is java.lang.NumberFormatException: For input string: "1,2,6"]]
Same request as above but with java pojo:
localhost:8080/test/param/test-java-1?projectIdIn2=1,2,3&projectIdIn3=1,2,4&projectIdIn4=1,2,5&projectIdIn5=1,2,6&projectIdIn6=1,2,7&projectIdIn8=1,2,9&projectIdIn1=1&projectIdIn1=3
It will return a JSON:
{"projectIdIn1":[1,3],"projectIdIn2":["1","2","3"],"projectIdIn5":[1,2,6],"projectIdIn6":["1","2","7"]}
Request for:
localhost:8080/test/param/test-3?projectIdIn2=1,2,3&projectIdIn3=1,2,4&projectIdIn4=1,2,5&projectIdIn5=1,2,6&projectIdIn6=1,2,7&projectIdIn7=1,2,8&projectIdIn8=1,2,9&enum2=beijing,shanghai&projectIdIn1=5&projectIdIn1=6
Result:
{"projectIdIn1":[5,6],"projectIdIn2":["1","2","3"],"projectIdIn3":[1,2,4],"projectIdIn4":["1","2","5"],"projectIdIn5":[1,2,6],"projectIdIn6":["1","2","7"],"projectIdIn7":[1,2,8],"projectIdIn8":["1","2","9"],"enum1":null,"enum2":["beijing","shanghai"],"enum3":null}
@RestController
@RequestMapping("/test/param")
class TestController {
@GetMapping("/test-java-1")
fun test1(criteria: JavaCriteria): JavaCriteria {
return criteria
}
@GetMapping("/test-1")
fun test1(criteria: SimpleCriteria): SimpleCriteria {
return criteria
}
@GetMapping("/test-3")
fun test3(
@RequestParam projectIdIn1: Set<Long>? = null,
@RequestParam projectIdIn2: Set<String>? = null,
@RequestParam projectIdIn3: Set<ProjectId>? = null,
@RequestParam projectIdIn4: Set<ProjectIdNew>? = null,
@RequestParam projectIdIn5: List<Long>? = null,
@RequestParam projectIdIn6: List<String>? = null,
@RequestParam projectIdIn7: List<ProjectId>? = null,
@RequestParam projectIdIn8: List<ProjectIdNew>? = null
): SimpleCriteria {
return SimpleCriteria(
projectIdIn1,
projectIdIn2,
projectIdIn3,
projectIdIn4,
projectIdIn5,
projectIdIn6,
projectIdIn7,
projectIdIn8
)
}
}
typealias ProjectId = Long
typealias ProjectIdNew = String
data class SimpleCriteria(
val projectIdIn1: Set<Long>? = null, // fails to convert 1,2
val projectIdIn2: Set<String>? = null, // Get a list with one element "1,2"
val projectIdIn3: Set<ProjectId>? = null, // fails to convert 1,2
val projectIdIn4: Set<ProjectIdNew>? = null, // Get a list with one element "1,2"
val projectIdIn5: List<Long>? = null, // fails to convert 1,2
val projectIdIn6: List<String>? = null, // Get a list with one element "1,2"
val projectIdIn7: List<ProjectId>? = null, // fails to convert 1,2
val projectIdIn8: List<ProjectIdNew>? = null // Get a list with one element "1,2"
)
public class JavaCriteria {
private Set<Long> projectIdIn1;
private Set<String> projectIdIn2;
private List<Long> projectIdIn5;
private List<String> projectIdIn6;
public JavaCriteria() {
}
public Set<Long> getProjectIdIn1() {
return projectIdIn1;
}
public void setProjectIdIn1(final Set<Long> projectIdIn1) {
this.projectIdIn1 = projectIdIn1;
}
public Set<String> getProjectIdIn2() {
return projectIdIn2;
}
public void setProjectIdIn2(final Set<String> projectIdIn2) {
this.projectIdIn2 = projectIdIn2;
}
public List<Long> getProjectIdIn5() {
return projectIdIn5;
}
public void setProjectIdIn5(final List<Long> projectIdIn5) {
this.projectIdIn5 = projectIdIn5;
}
public List<String> getProjectIdIn6() {
return projectIdIn6;
}
public void setProjectIdIn6(final List<String> projectIdIn6) {
this.projectIdIn6 = projectIdIn6;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final JavaCriteria that = (JavaCriteria) o;
return Objects.equals(projectIdIn1, that.projectIdIn1) &&
Objects.equals(projectIdIn2, that.projectIdIn2) &&
Objects.equals(projectIdIn5, that.projectIdIn5) &&
Objects.equals(projectIdIn6, that.projectIdIn6);
}
@Override
public int hashCode() {
return Objects.hash(projectIdIn1, projectIdIn2, projectIdIn5, projectIdIn6);
}
@Override
public String toString() {
return "JavaCriteria{" +
"projectIdIn1=" + projectIdIn1 +
", projectIdIn2=" + projectIdIn2 +
", projectIdIn5=" + projectIdIn5 +
", projectIdIn6=" + projectIdIn6 +
'}';
}
}
Comment From: bclozel
Duplicates spring-projects/spring-framework#25815 Please don't open multiple instances of the same issue.
Comment From: Blackdread
ok, I thought this issue might be more related to spring boot but not sure.