I am trying to send a list of Javers Changes as JSON via a REST api. While Jackson can handle Java 8 Optionals via loading the respective module it fails to serialize the Change object. When i create a class with Optionals myself the serialization works as expected.
To reproduce one can run the following groovy script:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
import org.javers.core.JaversBuilder
import org.javers.repository.jql.QueryBuilder
@Grapes([
@Grab("com.fasterxml.jackson.core:jackson-core:2.8.3"),
@Grab(group='com.fasterxml.jackson.datatype', module='jackson-datatype-jdk8', version='2.8.3'),
@Grab('org.javers:javers-core:2.3.0')]
)
class Test {
def bar
def baz
Test(){
baz = "baz"
bar = "bar"
}
}
def test = new Test()
def javers = JaversBuilder.javers().build()
javers.commit("user", test)
test.bar = "foo"
javers.commit("user", test)
def objectMapper = new ObjectMapper()
objectMapper.registerModule(new Jdk8Module())
println objectMapper.writeValueAsString(javers.findChanges(QueryBuilder.anyDomainObject().build()))
This outputs:
[
{
"commitMetadata": {
"empty": false,
"present": true
},
"propertyName": "bar",
"left": "bar",
"right": "foo",
"affectedGlobalId": {
"typeName": "Test"
},
"affectedLocalId": null,
"affectedObject": {
"empty": true,
"present": false
}
}
]
A custom class gets serialzed as expected:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
@Grapes([
@Grab("com.fasterxml.jackson.core:jackson-core:2.8.3"),
@Grab(group='com.fasterxml.jackson.datatype', module='jackson-datatype-jdk8', version='2.8.3')]
)
class Test2 {
def bar
def baz
Test2(){
baz = Optional.of("baz")
bar = "bar"
}
}
def test = new Test2()
def objectMapper = new ObjectMapper()
objectMapper.registerModule(new Jdk8Module())
println objectMapper.writeValueAsString(test)
Output:
{
"bar": "bar",
"baz": "baz"
}
What is special about the Javers Change class, that Jackson refuses to serialze the Optionals?
Jackson doesn't know Javers' Optionals and tries to serialize them as a standard Java Bean which is wrong in this case. You can fix it by writing a custom serializer for Jackson.
Javers' Optionals exists because replacing them with Java8 Optionals would brake Java7 clients.