Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用jackson以不同方式序列化同一实体的相同属性_Java_Json_Serialization_Jackson - Fatal编程技术网

Java 如何使用jackson以不同方式序列化同一实体的相同属性

Java 如何使用jackson以不同方式序列化同一实体的相同属性,java,json,serialization,jackson,Java,Json,Serialization,Jackson,假设您有这个实体: class Foo{ String propA; String propB; } 您希望序列化一个API,如: {propA: "ola", propB: "Holla"} 对于另一个API,如: {fooPropA: "ola", fooPropB: "Holla"} 如何使用jackson和使用相同的实体来实现这一点。创建两个不同的实体不是一个选项:)您可以通过使用Jackson的模块功能来实现这一点。 基本上,每个API都有自己的ObjectMapper,

假设您有这个实体:

class Foo{
 String propA;
 String propB;
}
您希望序列化一个API,如:

{propA: "ola",
 propB: "Holla"}
对于另一个API,如:

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

如何使用jackson和使用相同的实体来实现这一点。创建两个不同的实体不是一个选项:)

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

基本上,每个API都有自己的ObjectMapper,并将配置不同的模块。通过这种方式,您可以为同一个类创建2个序列化程序,并将它们注册到相应的模块上。更多阅读可以在这里找到

但是,请注意序列化程序是按特定顺序加载的。首先,它尝试获取带注释的,如果没有找到,它将尝试从模块中获取已注册的。所以,例如,若您用serializer对类进行注释,那个么将选择该序列化器(FooSerializer),而不是在模块中配置的序列化器(MySecondFooSerializer)


有几种方法可以实现这一点。您可以启用自定义序列化程序(已在@se_vedem中介绍)、注册注释以更改相应类的属性名称等等

但是,如果您只想在所有属性名称中添加字符串前缀,那么可能是最合适的。命名策略类可以访问序列化对象类型信息,因此您可以决定是否更改属性名称

以下是使用自定义注释定义前缀的示例:

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

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

好提示,但这会影响该ObjectMapper序列化的所有实体。我一直在寻找一种隔离某些实体的方法,比如100个实体中只有2个需要这种特殊的序列化处理。@sa_vedem您想如何区分这些实体?基于类型信息或属性值?一个将使用ObjectMapperA序列化,另一个使用ObjectMapperB@sa_vedem所以通过ObjetMapper影响所有实体是可以的,对吧?对不起,我在你的第一个问题上回答得很糟糕。我想在类型信息上区分它们。
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"}