【问题标题】:How to serialize differently the same properties of the same entity using jackson如何使用杰克逊以不同方式序列化同一实体的相同属性
【发布时间】:2014-08-05 11:46:13
【问题描述】:

假设你有这个实体:

class Foo{
 String propA;
 String propB;
}

并且您想为一个 API 序列化,例如:

{propA: "ola",
 propB: "Holla"}

对于另一个 API,例如:

{fooPropA: "ola",
 fooPropB: "Holla"}

如何使用杰克逊和使用相同的实体来实现这一点。不能创建 2 个不同的实体 :)

【问题讨论】:

    标签: java json serialization jackson


    【解决方案1】:

    有几种方法可以实现这一目标。您可以启用自定义序列化程序(@se_vedem 已涵盖),注册一个注释 introspector 以更改相应类的属性名称等等。

    但是,如果您只愿意为所有属性名称添加一个字符串前缀,那么the Jackson property name strategy 可能是最合适的。命名策略类可以访问序列化的对象类型信息,因此您可以决定是否更改属性名称。

    这是一个使用定义前缀的自定义注释的示例:

    public class JacksonNameStrategy {
        @Retention(RetentionPolicy.RUNTIME)
        public static @interface PropertyPrefix {
            String value();
        }
    
        @PropertyPrefix("foo_")
        public static class Foo {
            public String propA;
            public String propB;
    
            public Foo(String propA, String propB) {
                this.propA = propA;
                this.propB = propB;
            }
        }
    
        public static void main(String[] args) throws JsonProcessingException {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategyBase());
            System.out.println(mapper.writeValueAsString(new Foo("old", "Holla")));
        }
    
        private static class MyPropertyNamingStrategyBase extends PropertyNamingStrategy {
    
            @Override
            public String nameForField(MapperConfig<?> config,
                                       AnnotatedField field,
                                       String defaultName) {
                PropertyPrefix ann = field.getDeclaringClass().getAnnotation(PropertyPrefix.class);
                if (ann != null) {
                    return ann.value() + defaultName;
                }
                return super.nameForField(config, field, defaultName);
            }
        }
    }
    

    输出:

    {"foo_propA":"old","foo_propB":"Holla"}
    

    在您的 API 方法中,您可以在两个 ObjectMapper 实例之间进行选择,一个使用默认命名策略,一个使用自定义命名策略。

    【讨论】:

    • 好的提示,但这会影响由该 ObjectMapper 序列化的所有实体。我一直在寻找一种隔离某些实体的方法,比如 100 个实体中只有 2 个需要这种特殊的序列化处理。
    • @sa_vedem 您想如何区分实体?基于类型信息还是属性值?
    • 事实上,一个使用 ObjectMapperA 序列化,另一个使用 ObjectMapperB 进行序列化
    • @sa_vedem 所以通过 ObjetMapper 影响所有实体没问题,对吧?
    • 对不起,我在你的第一个问题上回答得很糟糕。我想根据类型信息来区分它们。
    【解决方案2】:

    您可以使用 Jackson 的模块功能来实现这一点。

    基本上,每个 API 都有自己的 ObjectMapper,它们将配置不同的模块。这样,您可以为同一个类创建 2 个序列化程序并将它们注册到相应的模块上。更多阅读可以在这里找到http://wiki.fasterxml.com/JacksonFeatureModules

    但是,请注意,序列化程序是按特定顺序加载的。首先它会尝试获取带注释的,如果没有找到,它将尝试从模块中获取那些注册的。因此,例如,如果您的类使用序列化器进行了注释,那么将选择序列化器(FooSerializer)而不是模块(MySecondFooSerializer)中配置的序列化器。

    @JsonSerialize(using = FooSerializer.class)
    class Foo{
     String propA;
     String propB;
    }
    
    module.addSerializer(Foo.class, new MySecondFooSerializer());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 2021-11-08
      • 2020-08-04
      • 2023-04-10
      • 1970-01-01
      相关资源
      最近更新 更多