Description
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 class TestObject(
val name: String
) {
var cellphone: String = ""
}
@Controller
class TestResolver {
@MutationMapping
fun createTestObject(
@Argument testObject: TestObject
) {
println(testObject.cellphone) // Will be empty
}
}
input TestObjectInput {
name: String!
cellphone: String!
}
type Mutation {
createTestObject(testObject: TestObjectInput!)
}
schema {
mutation: Mutation
}
mutation createTestObjectWithoutValidation($testObject: TestObjectInput!) {
createTestObjectWithoutValidation(testObject: $testObject)
}
{
"testObject": {
"name": "Felipe",
"cellphone": "(41) 98765-4321"
}
}
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