4 votes

Sérialiseur personnalisé GSON pour Map avec des clés Enum

L'objet que je sérialise contient une carte dont les clés sont des Enums. Ces Enums ont une variable. Lorsque je le sérialise avec GSON, je voudrais que le JSON résultant ait la variable Enum au lieu du nom par défaut de l'Enum. J'ai essayé de créer un sérialiseur personnalisé et de l'enregistrer, mais cela ne fonctionne pas. Voici mon code.

Le contrôleur :

@Controller
public class CheckoutClientController {

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

@InitBinder
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();
    host.append(request.getScheme()).append("://");
    host.append(request.getServerName());
    host.append(":").append(request.getServerPort());

    checkoutClientConfig.setWlcHost(host.toString());
    checkoutClientConfig.setClientId("clientId");
    checkoutClientConfig.setAppId("appId");
    checkoutClientConfig.setId("wlc-widget");

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

    options.put(CheckoutClientConfigurationOption.SHOW_ORDER_CONFIRMATION,
            Boolean.valueOf(this.settingsReader.getSettingValue(SettingsConstants.SHOW_ORDER_CONFIRMATION).getValue()));
    options.put(CheckoutClientConfigurationOption.REMOVE_CART_ITEMS,
            Boolean.valueOf(this.settingsReader.getSettingValue(SettingsConstants.REMOVE_CART_ITEMS).getValue()));

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

CheckoutClientConfigurationDto (sans tous les getters/setters passe-partout) :

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;
}
}

CheckoutClientConfigurationOption :

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;
}
}

Mon sérialiseur GSON personnalisé :

public class CheckoutClientConfigurationOptionGsonSerializer implements JsonSerializer<CheckoutClientConfigurationOption> {

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

}

Mon configurateur GSON personnalisé :

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;
}

}

Le XML :

<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>
            <entry key="com.sfweb.dto.CheckoutClientConfigurationOption">
                <bean class="com.sfweb.dto.serializer.CheckoutClientConfigurationOptionGsonSerializer" />
            </entry>
        </util:map>
    </property>
</bean>

<bean class="com.google.gson.Gson" factory-bean="gsonConfigurer" factory-method="create" />

J'ai également un désérialiseur personnalisé, comme vous pouvez le voir dans le XML. Celui-ci fonctionne sans problème. J'ai exécuté en mode débogage et la ligne dans CheckoutClientConfigurationOptionGsonSerializer n'est jamais activée. J'ai vérifié que l'objet gson sur lequel j'appelle toJson() contient le sérialiseur personnalisé. Je ne suis donc pas sûr de l'origine du problème. J'ai l'impression qu'il me manque juste une pièce.

Je veux que le JSON résultant dise "showSavedAddresses", mais au lieu de cela, il dit "SHOW_SAVED_ADDRESSES". Merci d'avance pour votre aide !

2voto

darkporter Points 7552

En lisant la documentation sur GsonBuilder#enableComplexMapKeySerialization (en anglais) Je vois ça :

L'implémentation par défaut de la sérialisation des cartes utilise toString() sur la clé

Donc, il n'exécute pas votre TypeAdapter sur les clés de la carte par défaut. J'ai essayé d'appeler simplement cette méthode et j'ai obtenu que mes enums s'affichent comme des chaînes numériques.

0voto

Jesse Wilson Points 8455

Vous seriez bien inspiré d'étudier Documentation de TypeAdapterFactory . Il inclut un exemple qui formate les enums en minuscules ; vous pouvez le modifier selon vos propres besoins.

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) {
          out.nullValue();
        } else {
          out.value(toLowercase(value));
        }
      }

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X