Custom GSON Serializer for Enum Key Cards

The object I'm serializing contains a map with keys that are enumerations. These enums have a variable. When I serialize it with GSON, I would like the resulting JSON to have an Enum variable instead of the default Enum name. I tried to create my own serializer and register it, but that doesn't do the trick. Here is my code.


public class CheckoutClientController {

private Gson gson;
private RequestHelper requestHelper;
private SettingsReader settingsReader;

public void initBinder(final WebDataBinder binder) {
    binder.registerCustomEditor(CheckoutConfigurationDto.class, new JsonDeserializerPropertyEditor<CheckoutConfigurationDto>(gson, CheckoutConfigurationDto.class));

 * Handles requests to the Checkout Client page, which is the outer wrapper that includes the white label checkout (WLC) iframe. Sets up the configuration
 * data needed to pass to the WLC server.
 * @return the model and view
@RequestMapping(value = "/checkout/checkout-client.ep", method = RequestMethod.GET)
public ModelAndView showPage(HttpServletRequest request) {
    CheckoutClientConfigurationDto checkoutClientConfig = new CheckoutClientConfigurationDto();

    StringBuilder host = new StringBuilder();


    Map<CheckoutClientConfigurationOption, Boolean> options = checkoutClientConfig.getOptions();


    return new ModelAndView(ViewConstants.CHECKOUT_CLIENT_TEMPLATE_PATH, "checkoutClientConfig", gson.toJson(checkoutClientConfig));


CheckoutClientConfigurationDto (minus all templates / setters):

public class CheckoutClientConfigurationDto implements Dto {

private String wlcHost;

private String clientId;

private String appId;

private String id;

private Map<CheckoutClientConfigurationOption, Boolean> options;

public CheckoutClientConfigurationDto() {
    products = new ArrayList<ProductDto>();
    options = new HashMap<CheckoutClientConfigurationOption, Boolean>();

public Map<CheckoutClientConfigurationOption, Boolean> getOptions() {
    return options;

public void setOptions(final Map<CheckoutClientConfigurationOption, Boolean> options) {
    this.options = options;



public enum CheckoutClientConfigurationOption {

SHOW_SAVED_ADDRESSES("showSavedAddresses", true),
SHOW_CART_SUMMARY("showCartSummary", true),
REMOVE_CART_ITEMS("removeCartItems", true),
SHOW_DISCOUNT_FIELD("showDiscountField", true),
SHOW_VAT_CODE("showVatCode", true),
SHOW_ORDER_CONFIRMATION("showOrderConfirmation", true),
SHOW_CANCEL_BUTTON("showCancelButton", false),
SINGLE_PAGE_CHECKOUT("singlePageCheckout", false),
SEND_ORDER_CONFIRMATION_EMAIL("sendOrderConfirmationEmail", true),
SEND_SHIPPING_CONFIRMATION_EMAIL("sendShippingConfirmationEmail", true);

private String optionName;

private boolean defaultValue;

private CheckoutClientConfigurationOption(final String optionName, final boolean defaultValue) {
    this.optionName = optionName;
    this.defaultValue = defaultValue;

public boolean getDefautValue() {
    return defaultValue;

public String getOptionName() {
    return optionName;


My custom GSON serializer:

public class CheckoutClientConfigurationOptionGsonSerializer implements JsonSerializer<CheckoutClientConfigurationOption> {

public JsonElement serialize(CheckoutClientConfigurationOption src, Type typeOfSrc, JsonSerializationContext context) {
    return new JsonPrimitive(src.getOptionName());



My custom GSON config:

public class GsonConfigurer {

private Map<Class<?>, Object> typeAdapterMap;

public Gson create() {
    final GsonBuilder gsonBuilder = new GsonBuilder();

    for (final Entry<Class<?>, Object> typeAdapterMapping : typeAdapterMap.entrySet()) {
        gsonBuilder.registerTypeAdapter(typeAdapterMapping.getKey(), typeAdapterMapping.getValue());

    return gsonBuilder.create();

protected Map<Class<?>, Object> getTypeAdapterMap() {
    return typeAdapterMap;

public void setTypeAdapterMap(final Map<Class<?>, Object> typeAdapterMap) {
    this.typeAdapterMap = typeAdapterMap;




<bean id="gsonConfigurer" class="com.sfweb.gson.GsonConfigurer">
    <property name="typeAdapterMap">
        <util:map key-type="java.lang.Class">
            <entry key="com.sfweb.dto.CheckoutConfigurationOption">
                <bean class="com.sfweb.dto.deserializer.CheckoutConfigurationOptionGsonDeserializer" />
            <entry key="com.sfweb.dto.CheckoutClientConfigurationOption">
                <bean class="com.sfweb.dto.serializer.CheckoutClientConfigurationOptionGsonSerializer" />

<bean class="" factory-bean="gsonConfigurer" factory-method="create" />


I also have a custom deserializer as you can see in the XML. This works without issue. I was working in debug mode and the line in the CheckoutClientConfigurationOptionGsonSerializer never got through. I have verified that the gson object that I call toJson () on has its own serializer in it. So I'm not sure what the problem is. I have a feeling that I just missed one part.

I want the resulting JSON to say "showSavedAddresses" but it says "SHOW_SAVED_ADDRESSES" instead. Thanks in advance for your help!


source to share

2 answers

Reading the documentation on GsonBuilder # enableComplexMapKeySerialization I see this:

The default map serialization implementation uses toString () for the key

This way it doesn't trigger your keys TypeAdapter

on the map by default. I tried just calling this method and got my enums as numeric strings.



You will find it helpful to study the TypeAdapterFactory documentation . It includes an example that formats enums as lowercase; you can change this to suit your needs.

public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory {
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    Class<T> rawType = (Class<T>) type.getRawType();
    if (!rawType.isEnum()) {
      return null;

    final Map<String, T> lowercaseToConstant = new HashMap<String, T>();
    for (T constant : rawType.getEnumConstants()) {
      lowercaseToConstant.put(toLowercase(constant), constant);

    return new TypeAdapter<T>() {
      public void write(JsonWriter out, T value) throws IOException {
        if (value == null) {
        } else {

      public T read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
          return null;
        } else {
          return lowercaseToConstant.get(reader.nextString());

  private String toLowercase(Object o) {
    return o.toString().toLowerCase(Locale.US);




All Articles