2012-03-23 2 views
3

직렬화하는 개체에 Enums 키가있는지도가 포함되어 있습니다. 그 Enum에는 변수가 있습니다. GSON으로 직렬화 할 때 결과 JSON에 기본 Enum 이름 대신 Enum 변수가 있어야합니다. 사용자 지정 serializer를 만들고 등록하려고 시도했지만 트릭을 수행하지는 않습니다. 여기 내 코드가있다. 열거 형 키가있는 Map의 GSON 사용자 지정 serializer

컨트롤러 :

@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 (마이너스 모든 상용구 게터/세터) :

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

내 사용자 정의 GSON 시리얼 :

public class CheckoutClientConfigurationOptionGsonSerializer implements JsonSerializer<CheckoutClientConfigurationOption> { 

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

} 

내 사용자 정의 GSON Configurer에 :

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

} 

XML은 : 당신이 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" /> 

또한, 사용자 정의 디시리얼라이저 있습니다. 그것은 문제없이 작동합니다. 디버그 모드에서 실행되었고 CheckoutClientConfigurationOptionGsonSerializer의 줄이 절대로 안됩니다. 나는 Json()을 호출하는 gson 객체가 사용자 정의 직렬자를 가지고 있는지 확인했다. 그래서 나는 그 문제가 무엇인지 모른다. 나는 한 조각을 잃어버린 느낌이 들었다.

나는 "showSavedAddresses"를 말할 결과 JSON을 원하고, 대신 그것은 "SHOW_SAVED_ADDRESSES"을 말하고있다. 도움에 미리 감사드립니다!

+0

동일한 문제가 있습니다. 내 생각 엔 JS 객체의 키가 궁극적으로 문자열이어야하므로 선호하는'value.toJsonAndRunCustomSerializer(). toString()'대신 'value.toString()'을 실행하는 것입니다. – jpsimons

답변

0

당신은 잘 TypeAdapterFactory's documentation을 연구하기 위해 제공 될 것입니다. 열거 형을 소문자로 형식화하는 예제가 포함되어 있습니다. 이것을 자신의 필요에 맞게 수정할 수 있습니다.

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); 
    } 
} 
+0

나는이 경로를 시험해 보았고 같은 결과를 얻었다. 문제는 내 열거 형이 내지도의 키로 포함된다는 사실입니다. 내 DTO에서 단일 변수로 가지고 있으면 enum을 소문자로 직렬화하지만 맵의 키로 사용하면 내 사용자 지정 serializer 또는 사용자 지정 형식 어댑터가 호출되지 않습니다. –

2

GsonBuilder#enableComplexMapKeySerialization에 설명서를 읽고 나는이 참조 :

지도 직렬화의 기본 구현은 그래서 당신의 TypeAdapter를 실행하지 않습니다 키

에 toString()를 사용 기본적으로지도 키입니다. 간단히이 메서드를 호출하고 열거 형을 숫자 문자열로 표시하려고했습니다.