简体   繁体   English

动态更改Json密钥名称-Jackson

[英]Change Json key name dynamically - Jackson

I have a java class like : 我有一个类似的Java类:

class TestJsonClass {
    private String propertyA;
    private String propertyB;
    private String propertyC;
}

Now during runtime i want to give different property names for each of the property, and not a static one using @JsonProperty("sample") 现在,在运行时,我想为每个属性提供不同的属性名称,而不是使用@JsonProperty(“ sample”)的静态属性名称

How do I accomplish this? 我该如何完成? I am using Jackson library ad Spring MVC 我正在使用Jackson图书馆广告Spring MVC

Thanks in advance... 提前致谢...

You can make use of Modules for this purpose. 为此,您可以使用模块 This is the easiest solutions to your problem. 这是解决问题的最简单方法。 Here is an example: 这是一个例子:

A simple class that can carry your property-name-mappings for each request: 一个简单的类,可以为每个请求携带您的属性名称映射:

public class PropertyNameMapper {
    // The class for which the mappings need to take place.
    public Class<?> classToFilter;
    // The mappings property names. Key would be the existing property name
    // value would be name you want in the ouput.
    public Map<String, String> nameMappings = Collections.emptyMap();

    public PropertyNameMapper(Class<?> classToFilter, Map<String, String> nameMappings) {
        this.classToFilter = classToFilter;
        this.nameMappings = nameMappings;
    }
}

A custom BeanPropertyWriter that will be used for specifying the output name for the properties. 一个自定义BeanPropertyWriter ,将用于指定属性的输出名称。

public class MyBeanPropertyWriter extends BeanPropertyWriter {
    // We would just use the copy-constructor rather than modifying the
    // protected properties. This is more in line with the current design
    // of the BeanSerializerModifier class (according to its documentation).
    protected MyBeanPropertyWriter(BeanPropertyWriter base, String targetName) {
        super(base, new SerializedString(targetName));
    }

}

Now, a custom BeanSerializerModifier that is called each time to allow you to modify the serialized properties. 现在,每次调用一个自定义BeanSerializerModifier ,以允许您修改序列化的属性。

public class MySerializerModifier extends BeanSerializerModifier {

    public List<BeanPropertyWriter> changeProperties(
            SerializationConfig config, BeanDescription beanDesc,
            List<BeanPropertyWriter> beanProperties) {

        List<PropertyNameMapper> propertyMappings = getNameMappingsFromRequest();
        PropertyNameMapper mapping = mappingsForClass(propertyMappings,
                beanDesc.getBeanClass());

        if (mapping == null) {
            return beanProperties;
        }

        List<BeanPropertyWriter> propsToWrite = new ArrayList<BeanPropertyWriter>();
        for (BeanPropertyWriter propWriter : beanProperties) {
            String propName = propWriter.getName();
            String outputName = mapping.nameMappings.get(propName);
            if (outputName != null) {
                BeanPropertyWriter modifiedWriter = new MyBeanPropertyWriter(
                        propWriter, outputName);
                propsToWrite.add(modifiedWriter);
            } else {
                propsToWrite.add(propWriter);
            }
        }
        return propsToWrite;
    }

    private List<PropertyNameMapper> getNameMappingsFromRequest() {
        RequestAttributes requestAttribs = RequestContextHolder
                .getRequestAttributes();
        List<PropertyNameMapper> nameMappings = (List<PropertyNameMapper>) requestAttribs
                .getAttribute("nameMappings",
                        RequestAttributes.SCOPE_REQUEST);
        return nameMappings;
    }

    private PropertyNameMapper mappingsForClass(
            List<PropertyNameMapper> nameMappings, Class<?> beanClass) {
        for (PropertyNameMapper mapping : nameMappings) {
            if (mapping.classToFilter.equals(beanClass)) {
                return mapping;
            }
        }
        return null;
    }
}

Now, you need a custom Module to be able to customize the output using the above created BeanSerializerModifier : 现在,您需要一个自定义模块 ,以便能够使用上面创建的BeanSerializerModifier自定义输出:

public class MyModule extends Module {

    @Override
    public String getModuleName() {
        return "Test Module";
    }

    @Override
    public void setupModule(SetupContext context) {
        context.addBeanSerializerModifier(new MySerializerModifier());
    }

    @Override
    public Version version() {
        // Modify if you need to.
        return Version.unknownVersion();
    }
}

Now register this module with your ObjectMapper . 现在向您的ObjectMapper注册该模块。 You can get the Jackson HTTP message converter from your spring application context, and get its object mapper. 您可以从spring应用程序上下文中获取Jackson HTTP消息转换器,并获取其对象映射器。

// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())

And that's it. 就是这样。 This is the easiest way to customize serialization of your properties dynamically. 这是动态自定义属性序列化的最简单方法。

To use this, create a List of PropertyNameMappers and add it as an attribute (named "nameMappings" in this example) in the current request. 若要使用此方法,请创建PropertyNameMappersList ,并将其添加为当前请求中的属性(在本示例中为“ nameMappings”)。

This is an example, not production-ready code. 这是一个示例,不是可用于生产的代码。 You might probably need to add null-checks and things like that. 您可能需要添加空检查和类似的东西。 Also, a few minor adjustments might be needed based on the version of the libraries you are using. 另外,根据您使用的库的版本,可能需要进行一些小的调整。

If the solution doesn't work for you, let me know the problems you are facing. 如果该解决方案对您不起作用,请让我知道您面临的问题。

You could inject a custom PropertyNamingStrategy into the ObjectMapper that's used in deserialization. 您可以将自定义PropertyNamingStrategy注入反序列化中使用的ObjectMapper中。

Just set fields into the PropertyNamingStrategy at runtime, assuming you can map them to something like the default JsonPropertyName (eg propertyA, propertyB, propertyC). 只需在运行时将字段设置到PropertyNamingStrategy中,假设您可以将它们映射到默认JsonPropertyName之类的字段(例如propertyA,propertyB,propertyC)。

public class MyNamingStrategy extends PropertyNamingStrategy {

    String propertyAName, propertyBName, propertyCName;

    public MyNamingStrategy(String propANm, String propBNm, String propCNm) {
        this.propertyAName = propANm;
        //finish
    }

    @Override
    public String nameForField(MapperConfig<?> config, AnnotatedField field,
            String defaultName) {
        return convert(defaultName);
    }

    @Override
    public String nameForGetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        return convert(defaultName);
    }

    @Override
    public String nameForSetterMethod(MapperConfig<?> config,
            AnnotatedMethod method, String defaultName) {
        return convert(defaultName);
    }

    public String convert(String defaultName ){
        return defaultName.replace("propertyA", propertyAName).replace( //finish
    }

Finally you'd create an instance and inject it at runtime. 最后,您将创建一个实例并在运行时将其注入。 objectMapper.setNamingStrategy(myNamingStrategyInstance)); objectMapper.setNamingStrategy(myNamingStrategyInstance));

See this Cowtowncoder post for more on PropertyNamingStrategy: 有关PropertyNamingStrategy的更多信息,请参见此Cowtowncoder帖子:

Jackson 1.8: custom property naming strategies 杰克逊1.8:自定义媒体资源命名策略

Or this documentation: 或此文档:

github.com/FasterXML/jackson-docs/wiki/PropertyNamingStrategy github.com/FasterXML/jackson-docs/wiki/PropertyNamingStrategy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM