使用Jackson和Spring Boot的条件JsonProperty [英] Conditional JsonProperty using Jackson with Spring Boot

查看:99
本文介绍了使用Jackson和Spring Boot的条件JsonProperty的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spring Boot应用程序的任务是每隔这么几分钟就更新一次远程集成API.该应用程序可以部署到测试或产品环境,通过"application.properties"标志通知应用程序应该查看的终点.正在使用Jackson序列化POJO并将其推送到端点,并且JsonProperty批注包含将其推送到的API的字段ID.

  @JsonProperty("field_001)私有字符串名称;@JsonProperty("field_002)私有字符串地址; 

这些值的字段标签在测试端点上有所不同.因此测试端点可能希望属性映射为

  @JsonProperty("field_005)私有字符串名称;@JsonProperty("field_006)私有字符串地址; 

我希望能够利用Spring Boot本机支持基于配置文件的属性文件.要在运行时从外部属性文件中读取JsonProperty批注值.

例如,

可能有三个文件application.properties,application-test.properties和application-prod.properties.除了基于"spring.profiles.active"设置的原始属性文件之外,Spring Boot还可以读取test或prod属性.

...- test.properties将包含测试服务器字段的常量值.并且...- prod.properties将包含prod服务器字段的常量值.

嵌套注解,例如Spring的@Value标记,如下所示:

  @JsonProperty(@Value("$ {property.file.reference.here}))) 

似乎不起作用.

解决方案

我为重提一个老问题深表歉意,但仍然找不到令人满意的答案.

这是我使用扩展的 JacksonAnnotationIntrospector 的解决方案,它允许在 @JsonProperty 批注中使用 $ {environment.properties}

首先扩展内省者

 公共类DynamicJacksonAnnotationIntrospector扩展了JacksonAnnotationIntrospector {私人最终环境;公共DynamicJacksonAnnotationIntrospector(环境){this.environment =环境;}@Overridepublic PropertyName findNameForSerialization(注解a){PropertyName名称= super.findNameForSerialization(a);如果(name == null){返回null;}字符串simpleName = name.getSimpleName();返回PropertyName.construct(environment.resolvePlaceholders(simpleName),name.getNamespace());}//对于反序列化,我认为可以使用相同的机制,//只是重写`findNameForDeserialization`,尽管我还没有测试过} 

然后将其用于 ObjectMapper 配置

  @Configuration公共类ObjectMapperConfiguration {@豆角,扁豆公共ObjectMapper getObjectMapper(DynamicJacksonAnnotationIntrospector内省者){ObjectMapper映射器=新的ObjectMapper();SerializationConfig config = mapper.getSerializationConfig().withInsertedAnnotationIntrospector(introspector);mapper.setConfig(config);返回映射器;}@豆角,扁豆公共DynamicJacksonAnnotationIntrospector内省(环境){返回新的DynamicJacksonAnnotationIntrospector(environment);}} 

示例:

 公共类DynamicTestClass {@JsonProperty("$ {dynamic.property.name}")私有字符串dynamicPropertyName;//getters/setters} 

  @ContextConfiguration(classes = [ObjectMapperConfiguration])@TestPropertySource("classpath:test.properties")类DynamicJacksonAnnotationIntrospectorTest扩展了规范{@AutowiredObjectMapper映射器def应该从属性中找到序列化的名称"(){def bean =新的DynamicTestClass()bean.dynamicPropertyName ="qwerty"什么时候:def结果= mapper.writeValueAsString(bean)然后:结果=="{\" overriddenName \:\" qwerty \}"}} 

test.properties

  dynamic.property.name = overriddenName 

该解决方案是向下兼容的,因此您仍然可以在 @JsonProperty

中使用常量值

A Spring Boot application is tasked with updating a remote integration API every so many minutes. This application can be deployed to a test or prod environment, the application is informed of the end point it should be looking at through an "application.properties" flag. A POJO is being serialized with Jackson and pushed to the endpoint, with the JsonProperty annotations containing the field IDs for the API that it is being pushed to.

ie

@JsonProperty("field_001)
private String name;

@JsonProperty("field_002)
private String address;

The field labels for these values differ on the test endpoint. So the test endpoint might expect the properties to map as

@JsonProperty("field_005)
private String name;

@JsonProperty("field_006)
private String address;

I would like to be able to utilize the Spring Boot native support for profile based properties files. To read in the JsonProperty annotation values at run time from an external properties file.

So for example,

There might be three files application.properties, application-test.properties and application-prod.properties. Spring Boot could read in the test or prod properties in addition to the vanilla properties file based on the "spring.profiles.active" setting.

...-test.properties would contain the constant values for the test server fields. And ...-prod.properties would contain the constant values for the prod server fields.

Nesting annotations such as Spring's @Value tag, like this:

@JsonProperty(@Value("${property.file.reference.here})) 

doesn't seem to work.

解决方案

I apologize for reviving an old question however I still was not able to find satisfying answer.

Here's my solution using extended JacksonAnnotationIntrospector which allows to use ${environment.properties} within @JsonProperty annotation

First extend the introspector

public class DynamicJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {
    private final Environment environment;

    public DynamicJacksonAnnotationIntrospector(Environment environment) {
        this.environment = environment;
    }

    @Override
    public PropertyName findNameForSerialization(Annotated a) {
        PropertyName name = super.findNameForSerialization(a);
        if (name == null) {
            return null;
        }
        String simpleName = name.getSimpleName();
        return PropertyName.construct(environment.resolvePlaceholders(simpleName), name.getNamespace());
    }
    //For deserialization I think the same mechanism could be used,
    //just override `findNameForDeserialization`, although I haven't tested it
}

Then use it with ObjectMapper configuration

@Configuration
public class ObjectMapperConfiguration {
    @Bean
    public ObjectMapper getObjectMapper(DynamicJacksonAnnotationIntrospector introspector) {
        ObjectMapper mapper = new ObjectMapper();
        SerializationConfig config = mapper.getSerializationConfig().withInsertedAnnotationIntrospector(introspector);
        mapper.setConfig(config);
        return mapper;
    }

    @Bean
    public DynamicJacksonAnnotationIntrospector introspector(Environment environment) {
        return new DynamicJacksonAnnotationIntrospector(environment);
    }
}

Examples:

public class DynamicTestClass {
    @JsonProperty("${dynamic.property.name}")
    private String dynamicPropertyName;
    //getters/setters
}

@ContextConfiguration(classes = [
        ObjectMapperConfiguration
])
@TestPropertySource("classpath:test.properties")
class DynamicJacksonAnnotationIntrospectorTest extends Specification {
    @Autowired
    ObjectMapper mapper

    def "should find name for serialization from properties"() {
        def bean = new DynamicTestClass()
        bean.dynamicPropertyName = "qwerty"

        when:
        def result = mapper.writeValueAsString(bean)

        then:
        result == "{\"overriddenName\":\"qwerty\"}"
    }
}

test.properties

dynamic.property.name=overriddenName

The solution is reverse compatible so you can still use constant values in @JsonProperty

这篇关于使用Jackson和Spring Boot的条件JsonProperty的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆