【问题标题】:Serialize class based on one interface it implements with Jackson or Gson基于它与 Jackson 或 Gson 实现的一个接口序列化类
【发布时间】:2012-02-13 21:23:04
【问题描述】:

我有以下几点:

接口 I1 扩展了 Ia、Ib、Ic

一个接口 I2。

C 类实现了 I1、I2。这个类也有自己的 setter 和 getter。

C cInstance = 新 C():

//Jackson
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("somefile.json"), cInstance);

//Gson
Gson gson = new Gson();
String json = gson.toJson(cInstance);

输出将根据 C 的属性及其继承的内容进行 cInstance 序列化。 但是,我喜欢根据 I1 中的 setter/getter 对属性进行序列化(仅 I1 接口中表示的 cInstance 属性)。

Jackson 知道我有太多具有相同问题的类并且我无法修改类定义或添加注释,我该如何做到这一点。

同样的问题也适用于反序列化(根据接口反序列化)

谢谢

【问题讨论】:

    标签: serialization jackson deserialization gson


    【解决方案1】:

    首先,即使不直接添加注释,您也始终可以附加“混合注释”(参见wiki page)。有了这个,要使用的注释将是:

    @JsonSerialize(as=MyInterface.class)
    

    但如果你不想使用 mix-ins,你可以强制使用特定类型

    objectMapper.typedWriter(MyInterface.class).writeValue(....)
    

    【讨论】:

    • 它应该是 @JsonSerialize(as = MyInterface.class) 但不幸的是,这对我在 jackson 2.1.1 中不起作用。 using 属性用于指定 JsonSerializer 实现。
    • 是的,您是正确的——使用正确的值进行了编辑。我认为这实际上应该有效(尝试强制使用 Lists 之类的结构化值存在问题),但与属性值(可以正常工作)相比,根值是有问题的。
    • 现在的第二个选项看起来像 objectMapper.writerFor(UserResponse.class).writeValue... (Jackson 2.9.6)
    【解决方案2】:

    Jackson 的VisibilityChecker 提供了一种过滤某些属性的简单方法,特别是因为它允许您单独测试每个方法/字段的可见性(等于“是否会被序列化”)。

    至少这有助于序列化阶段。

    这是我所做的(使用 Jackson 版本 1.9.11):

    import org.codehaus.jackson.map.ObjectMapper;
    import org.codehaus.jackson.map.introspect.AnnotatedMethod;
    import org.codehaus.jackson.map.introspect.VisibilityChecker;
    
    public static class InterfaceVisibilityChecker extends VisibilityChecker.Std {
    
        private final Set<Method> visibleMethods;
    
        public InterfaceVisibilityChecker(Class<?>... clazzes) {
            super(JsonAutoDetect.Visibility.PUBLIC_ONLY);
    
            this.visibleMethods = new HashSet<>();
            for (Class<?> clz : clazzes) {
                this.visibleMethods.addAll(Arrays.asList(clz.getMethods()));
            }
        }
    
        @Override
        public boolean isGetterVisible(Method m) {
            return super.isGetterVisible(m) && isVisible(m);
        }
    
        @Override
        public boolean isGetterVisible(AnnotatedMethod m) {
            return isGetterVisible(m.getAnnotated());
        }
    
        private boolean isVisible(Method m) {
            for (Method visiMthd : visibleMethods) {
                if (isOverwriteMethod(m, visiMthd)) return true;
            }
            return false;
        }
    
        private boolean isOverwriteMethod(Method subMethod, Method superMethod) {
    
            // names must be equal
            if (! subMethod.getName().equals(superMethod.getName())) return false;
    
            // return types must be assignable
            if (! superMethod.getReturnType().isAssignableFrom(subMethod.getReturnType())) return false;
    
            // parameters must be equal
            if (! Arrays.equals(subMethod.getParameterTypes(), superMethod.getGenericParameterTypes())) return false;
    
            // classes must be assignable
            return superMethod.getDeclaringClass().isAssignableFrom(subMethod.getDeclaringClass());
        }
    }
    

    主要思想是使用标准VisibilityChecker 并通过检查方法是否在给定接口之一中声明来扩展它。

    使用以下 sn-p 将检查器应用于 ObjectMapper 实例:

    ObjectMapper om = new ObjectMapper();
    om.setVisibilityChecker(new InterfaceVisibilityChecker(
         I1.class, 
         I2.class, 
         Ia.class, 
         Ib.class, 
         Ic.class
    

    ));

    上面解决方案的一些cmets:

    1. 检查器不完整,如isIsGetterVisibleisFieldVisible 等方法可根据需要以类似方式处理。
    2. isOverwriteMethod 根本没有优化,它的检查可以被缓存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-10
      • 1970-01-01
      相关资源
      最近更新 更多