You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you have defined a class with some properties in the constructor and other properties being accessed via setter methods, only one of these (either the constructor or the setters) will be mapped.
data classTestObject(
valname:String
) {
var cellphone:String=""
}
@Controller
classTestResolver {
@MutationMapping
funcreateTestObject(
@Argument testObject:TestObject
) {
println(testObject.cellphone) // Will be empty
}
}
The issue arises because, in line 260 of the GraphQlArgumentBinder class, if the type object has a constructor with at least one argument, the binder uses that constructor to map the properties. If not, it defaults to using the setter methods to populate them. The idea with Kotlin is that you can create a data class with a primary constructor, where properties are used in equals() and hashCode(), but other properties, like the 'cellphone' property mentioned above, may not be. So, why not support both approaches, populate them via a constructor and setters?
GraphQlArgumentBinder.java
...
Constructor<?> constructor = BeanUtils.getResolvableConstructor(targetClass);
Object value = (constructor.getParameterCount() > 0) ?
bindMapToObjectViaConstructor(rawMap, constructor, targetType, bindingResult) :
bindMapToObjectViaSetters(rawMap, constructor, targetType, bindingResult);
...
Version: Spring GraphQL 1.3.1
Thanks, Felipe
The text was updated successfully, but these errors were encountered:
I also ran into this issue. There currently does not seem to be a way to use Spring for GraphQL with Kotlin data classes. I tried to define a secondary constructor without parameters but it is not used:
data class SomeEntity(var id: UUID?, [...]) {
constructor() : this(null, [...])
}
Stacktrace:
java.lang.IllegalStateException: Invalid number of parameter names: 8 for constructor public com.example.SomeEntity(java.util.UUID,[...],kotlin.jvm.internal.DefaultConstructorMarker)
at org.springframework.util.Assert.state(Assert.java:101) ~[spring-core-6.2.5.jar:6.2.5]
at org.springframework.beans.BeanUtils.getParameterNames(BeanUtils.java:672) ~[spring-beans-6.2.5.jar:6.2.5]
at org.springframework.graphql.data.GraphQlArgumentBinder.bindMapToObjectViaConstructor(GraphQlArgumentBinder.java:295) ~[spring-graphql-1.3.4.jar:1.3.4]
at org.springframework.graphql.data.GraphQlArgumentBinder.bindMap(GraphQlArgumentBinder.java:261) ~[spring-graphql-1.3.4.jar:1.3.4]
at org.springframework.graphql.data.GraphQlArgumentBinder.bindRawValue(GraphQlArgumentBinder.java:207) ~[spring-graphql-1.3.4.jar:1.3.4]
at org.springframework.graphql.data.GraphQlArgumentBinder.bind(GraphQlArgumentBinder.java:161) ~[spring-graphql-1.3.4.jar:1.3.4]
at org.springframework.graphql.data.GraphQlArgumentBinder.bind(GraphQlArgumentBinder.java:145) ~[spring-graphql-1.3.4.jar:1.3.4]
at org.springframework.graphql.data.query.QueryByExampleDataFetcher.buildExample(QueryByExampleDataFetcher.java:135) ~[spring-graphql-1.3.4.jar:1.3.4]
Edit: After further testing, I don't believe my issue is related to this. It is caused by the use of value classes in my case, so I've opened a separate issue #1186.
rstoyanchev
changed the title
Incorrect binding of the mapped object with a constructor that contains properties and defined setters
Support for both constructor and setter argument binding
Apr 17, 2025
If you have defined a class with some properties in the constructor and other properties being accessed via setter methods, only one of these (either the constructor or the setters) will be mapped.
The issue arises because, in line 260 of the GraphQlArgumentBinder class, if the type object has a constructor with at least one argument, the binder uses that constructor to map the properties. If not, it defaults to using the setter methods to populate them. The idea with Kotlin is that you can create a data class with a primary constructor, where properties are used in equals() and hashCode(), but other properties, like the 'cellphone' property mentioned above, may not be. So, why not support both approaches, populate them via a constructor and setters?
The text was updated successfully, but these errors were encountered: