Contribute in GitHub: Open doc issue

Creating custom serialization

You can create custom Jackson serializer and deserializer classes to use instead of the default classes. Then, create a custom ObjectMapper to use your custom classes.

Creating custom serializer and deserializer classes

Create a custom class that extends a Jackson StdSerializer or JsonDeserializer class.

Note: When you register a serializer or deserializer class for a Java type, all attributes in a Java object of that type use the class when mapped to and from JSON. For example, if you create and register a custom serializer to handle Date values, all Java objects that contain an attribute of the type Date are serialized by using this class.

The following code shows how to write a serializer class that converts Java attributes with a Cúram Date type to a JSON string that contains an ISO8601 date:

public class CustomDateSerializer extends StdSerializer<Date> implements ContextualSerializer {

  /** Constructor. */
  public CustomDateSerializer() {
    super(Date.class);
  }

  /** Convert a Curam Date attribute to a string, and write to the JSON generator. */
  @Override
  public void serialize(Date date, JsonGenerator generator, SerializerProvider provider) 
    throws IOException, JsonProcessingException {

    // handle null date value.
    if (date.equals(Date.kZeroDate)) {
      provider.defaultSerializeNull(generator);
      return;
    }

    Calendar calendar = date.getCalendar();
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setTimeZone(TimeZone.getDefault());
    generator.writeString(dateFormat.format(calendar.getTime()));
  }

  @Override
  public JsonSerializer<?> createContextual(SerializerProvider arg0, BeanProperty arg1) throws JsonMappingException {
    return new CustomDateSerializer();
  }
}

The following code shows how to write a deserializer class that converts a JSON string that contains an ISO8601 date to a Java attribute with a Cúram Date type:

import curam.util.type.Date;

public class CustomDateDeserializer extends JsonDeserializer<Date> implements ContextualDeserializer {

  /** Deserialize the content. */
  @Override
  public Date deserialize(JsonParser parser, DeserializationContext context)
      throws IOException, JsonProcessingException {

    final String dateString = parser.getText();

    // If the JSON string value is empty, this should be mapped to a Curam empty date.
    if (StringUtil.isNullOrEmpty(dateString)) {
      return Date.kZeroDate;
    }

    try {
      // ISO8601 format is 'yyyy-MM-dd'.
      final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

      // construct a Curam date.
      dateFormat.setTimeZone(TimeZone.getDefault());
      return new Date(dateFormat.parse(dateString).getTime());

    } catch (final ParseException e) {
      // return a valid default value to continue processing.
      return Date.kZeroDate;
    }

  }

  /** Handle null values. */
  @Override
  public curam.util.type.Date getNullValue() {
    return curam.util.type.Date.kZeroDate;
  }

  /** Simply need to return a new instance of this class. */
  @Override
  public JsonDeserializer<?> createContextual(DeserializationContext deserializationcontext, BeanProperty beanproperty) 
    throws JsonMappingException {

    return new CustomDateDeserializer();
  }
}

Registering the custom classes with Jackson

After you write your serializer and deserializer classes for any types that you want to handle differently to the default Jackson classes, you must register them with Jackson. Do this by creating a Jackson SimpleModule class and a Jackson ObjectMapperProvider class.

The following code shows how to create a custom SimpleModule class that adds the custom date serializer and deserializer classes that are shown in the previous examples:

public class CustomSimpleModule extends import com.fasterxml.jackson.databind.module.SimpleModule {

  public CustomSimpleModule() {

    addSerializer(curam.util.type.Date.class, new CustomDateSerializer());
    addDeserializer(curam.util.type.Date.class, new CustomDateDeserializer());
  }
}

Note: You register the serializer and deserializer classes for a Java type so that every Java attribute of that type is mapped to and from JSON by using the same serializer and deserializer classes. You cannot register multiple serializer or deserializer classes for the same Java type.

The following code shows how to create an ObjectMapper class and how to register the CustomSimpleModule class.

import javax.ws.rs.ext.ContextResolver;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CustomObjectMapperProvider implements ContextResolver<ObjectMapper> {

    public CustomObjectMapperProvider() {

        customObjectMapper = new ObjectMapper();
        customObjectMapper.registerModule(new CustomSimpleModule());

        // can also choose to enable or disable various features:
        defaultObjectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

    }
}

In addition to registering the CustomSimpleModule class, you can set or disable various Jackson features in the ObjectMapperProvider class. The previous code sample also shows how to disable the Jackson feature that writes dates as datestamps.

For more information about the Jackson features that you can enable or make unavailable, see SerializationFeature and DeserializationFeature in the Jackson documentation.