[alibaba/fastjson]怎样让一个Java Bean类同时支持静态key字段和动态key字段?

2024-05-23 912 views
2

背景:我使用fastjson生成elasticsearch客户端请求的json字符串。ES的json有一个奇怪的特性:使用动态的文档字段名称作为json key,同时,有些字段有是相对固定的。

静态key字段:直接声明相应类型的成员对象引用; (静态字段的json序列化依赖于成员对象的声明类型(基类类型),而不是实际类型(子类类型)) 动态key字段:extends HashMap<String, Object> (动态字段的value序列化依据的是value的实际类型)

import lombok.Getter; @Getter class ESXxxOptions extends HashMap<String, Object> { ESYyyOptions yyy = ...; }

然而,当我尝试这么做的时候,只有动态key生效。

回答

9

尝试使用JSONWare接口绕过这个问题:

class ESXxxOptions extends HashMap<String, Object> implements JSONAware{ ESYyyOptions yyy = ...;

@Override
public String toJSONString() {
    return toJSONObject().toString();
}

private Object toJSONObject() {
    JSONObject jsonObj = new JSONObject();
    if(pinyin!=null) {
        jsonObj.put("pinyin", JSONObject.toJSON(yyy));
    }
    for(String key : super.keySet()) {
        Object value = super.get(key);
        jsonObj.put(key, value);
    }
    return jsonObj;
}

}

新的问题:静态方法JSON.toJSONString()不能识别JSONAware接口……只能手工调用options.toJSONString()

3

class SerializeConfig:

        if (Map.class.isAssignableFrom(clazz)) {
            put(clazz, writer = MapSerializer.instance);
        } else if (List.class.isAssignableFrom(clazz)) {
            put(clazz, writer = ListSerializer.instance);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            put(clazz, writer = CollectionCodec.instance);
        } else if (Date.class.isAssignableFrom(clazz)) {
            put(clazz, writer = DateCodec.instance);
        } else if (JSONAware.class.isAssignableFrom(clazz)) {
            put(clazz, writer = JSONAwareSerializer.instance);
        }

这里Map接口的检测放在第一个,JSONAware还在后面,导致即使使用JSONAware机制,也无法让用户来定制JSON序列化。应该把JSONAware的检测放到第一个

5

尝试修改了一下:

   if (writer == null) {
        String className = clazz.getName();
        Class<?> superClass;

        if (JSONAware.class.isAssignableFrom(clazz)) {
            put(clazz, writer = JSONAwareSerializer.instance);
        } else if (Map.class.isAssignableFrom(clazz)) {
            put(clazz, writer = MapSerializer.instance);
        } else if (List.class.isAssignableFrom(clazz)) {
            put(clazz, writer = ListSerializer.instance);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            put(clazz, writer = CollectionCodec.instance);
        } else if (Date.class.isAssignableFrom(clazz)) {
            put(clazz, writer = DateCodec.instance);
        } /* else if (JSONAware.class.isAssignableFrom(clazz)) {
            put(clazz, writer = JSONAwareSerializer.instance);
        } */ else if (JSONSerializable.class.isAssignableFrom(clazz)) {
            put(clazz, writer = JSONSerializableSerializer.instance);

但是这样就导致options.toJSONString();调用运行时栈溢出了,但这实在是没有道理……

4

调试模式下,运行ok,执行的是我通过实现JSONAware接口toJSONString方法。 但是run模式下就遇到了奇怪的栈溢出错误?