Jackson ObjectMapper Config in Hippo CRISP
The recommended way for integrating external services in Hippo CMS is the CRISP API. The official documentation provides detailed enough instructions for installing, configuring and using it. However, when I needed to customize the default Jackson ObjectMapper
, it wasn't all that obvious how I could do it.
The REST service I had to call was returning a date value:
[ {
"name": "John",
"surname": "Doe",
"birthDate": "1980-05-01"
} ]
In my Java code I wanted to deserialize it into a LocalDate
:
public class Person {
// ...
private LocalDate birthDate;
// ...
public LocalDate getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
}
I configured a matching CRISP resource based on the example from the documentation, only removing the resourceLinkResolver
.
The code for calling the service and deserializing the result is pretty straightforward:
ResourceServiceBroker broker =
HippoServiceRegistry.getService(ResourceServiceBroker.class);
Resource resourceRoot = broker.resolve(DEMO_RESOURCE, "/persons");
ResourceCollection resourceCollection = resourceRoot.getChildren();
ResourceBeanMapper resourceBeanMapper = broker.getResourceBeanMapper(DEMO_RESOURCE);
Collection<Person> persons =
resourceBeanMapper.mapCollection(resourceCollection, Person.class);
Unfortunately, the deserialization failed:
java.lang.IllegalArgumentException: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1980-05-01')
To make it work, I would need to register the JavaTimeModule
. I started by adding the dependency to the site
module pom.xml
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
And the root pom.xml
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.jsr310.version}</version>
</dependency>
To configure the ObjectMapper
, I had to modify the CRISP resource configuration XML. The SimpleJacksonRestTemplateResourceResolver
has an objectMapper
property which can be used to provide a different ObjectMapper
:
<bean parent="abstractCrispSimpleJacksonRestTemplateResourceResolver"
class="org.onehippo.cms7.crisp.core.resource.jackson.SimpleJacksonRestTemplateResourceResolver">
<!-- ... -->
<property name="objectMapper">
<bean id="test"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="com.damirscorner.blog.samples.utils.ObjectMapperFactory" />
<property name="targetMethod" value="getObjectMapper" />
</bean>
</property>
</bean>
To make my work easier, I invoked a factory method inside which I configure the ObjectMapper
correctly:
public class ObjectMapperFactory {
private static ObjectMapper mapper;
public static ObjectMapper getObjectMapper() {
if (mapper == null)
{
mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
}
return mapper;
}
}
With all that set up, the ResourceBeanMapper
now used my custom ObjectMapper
for deserialization which resolved my issue with the LocalDate
.