I'm using Spring data rest with Kotlin and if I use data classes the associations via uri stops working with the error no String-argument constructor/factory method to deserialize from String value
Data class
@Entity
data class Comment(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
var author: String? = null,
var content: String? = null,
@ManyToOne
var post: Post? = null) {
}
If I use a simple class instead the association works fine.
@Entity
class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0
var author: String? = null
var content: String? = null
@ManyToOne
var post: Post? = null
}
The association is done via a POST request {"author":"John Doe","content":"Dummy Content", "post":"http://localhost:8080/post/33"}
Any ideia why I have this error when I use a data class and what can I do to use the association creation via uri and keep using data classes?
I did some investigation, and turns out Spring Data Rest uses a custom Jackson module to deserialize JSON into JPA entities: it uses PersistentEntityJackson2Module
class and using the inner class UriStringDeserializer
to resolve the concrete entities from entity URI references, http://localhost:8080/post/33
in your example.
Problem is, this custom deserialization only kicks in when the "standard deserialization" of Jackson is triggered: The one that uses empty constructor, then using setters to resolve & set the fields. At that moment, UriStringDeserializer
converts the string into the concrete entity - Post
instance of your example.
When you use a data class, the class neither has an empty constructor nor setters, therefore in BeanDeserializer#deserializeFromObject
method of Jackson, it branches into if (_nonStandardCreation)
being true, from there the call goes into BeanDeserializerBase#deserializeFromObjectUsingNonDefault
, but not handed over to PersistentEntityJackson2Module
anymore, and directly failing due to type mismatch between the constructor argument and the json value.
It seems you need to create a feature request for it to be implemented. If you decide to implement yourself, providing a _delegateDeserializer
to the BeanDeserializer might be a start (not sure).
However, I don't know how JPA itself plays with data classes in the first place - after all it tracks the entity state changes, but a data class cannot have state changes. So, it might not be possible to use data classes after all - better to keep in mind.
Note: You probably cannot simply extend/override PersistentEntityJackson2Module
because it is registered to multiple beans in RepositoryRestMvcConfiguration