Domain Object Representations (Object Mapping)

Spring Data REST returns a representation of a domain object that corresponds to the Accept type specified in the HTTP request.

Currently, only JSON representations are supported. Other representation types can be supported in the future by adding an appropriate converter and updating the controller methods with the appropriate content-type.

Sometimes, the behavior of the Spring Data REST ObjectMapper (which has been specially configured to use intelligent serializers that can turn domain objects into links and back again) may not handle your domain model correctly. There are so many ways you can structure your data that you may find your own domain model is not translated to JSON correctly. It is also sometimes not practical in these cases to try and support a complex domain model in a generic way. Sometimes, depending on the complexity, it is not even possible to offer a generic solution.

Adding Custom Serializers and Deserializers to Jackson’s ObjectMapper

To accommodate the largest percentage of use cases, Spring Data REST tries very hard to render your object graph correctly. It tries to serialize unmanaged beans as normal POJOs, and it tries to create links to managed beans where necessary. However, if your domain model does not easily lend itself to reading or writing plain JSON, you may want to configure Jackson’s ObjectMapper with your own custom mappings, serializers, and deserializers.

Abstract Class Registration

One key configuration point you might need to hook into is when you use an abstract class (or an interface) in your domain model. By default, Jackson does not know what implementation to create for an interface. Consider the following example:

@Entity
public class MyEntity {
  @OneToMany
  private List<MyInterface> interfaces;
}

In a default configuration, Jackson has no idea what class to instantiate when POSTing new data to the exporter. This is something you need to tell Jackson either through an annotation, or (more cleanly) by registering a type mapping by using a Module.

To add your own Jackson configuration to the ObjectMapper used by Spring Data REST, override the configureJacksonObjectMapper method. That method is passed an ObjectMapper instance that has a special module to handle serializing and deserializing PersistentEntity objects. You can register your own modules as well, as the following example shows:

@Override
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {

  objectMapper.registerModule(new SimpleModule("MyCustomModule") {

    @Override
    public void setupModule(SetupContext context) {
      context.addAbstractTypeResolver(
        new SimpleAbstractTypeResolver()
          .addMapping(MyInterface.class, MyInterfaceImpl.class));
    }
  });
}

Once you have access to the SetupContext object in your Module, you can do all sorts of cool things to configure Jackson’s JSON mapping. You can read more about how Module instances work on Jackson’s wiki.

Adding Custom Serializers for Domain Types

If you want to serialize or deserialize a domain type in a special way, you can register your own implementations with Jackson’s ObjectMapper, and the Spring Data REST exporter transparently handles those domain objects correctly. To add serializers from your setupModule method implementation, you can do something like the following:

@Override
public void setupModule(SetupContext context) {

  SimpleSerializers serializers = new SimpleSerializers();
  SimpleDeserializers deserializers = new SimpleDeserializers();

  serializers.addSerializer(MyEntity.class, new MyEntitySerializer());
  deserializers.addDeserializer(MyEntity.class, new MyEntityDeserializer());

  context.addSerializers(serializers);
  context.addDeserializers(deserializers);
}