使用 Jackson 和 Spring Boot 的条件 JsonProperty

Ald*_*usP 4 java spring json jackson spring-boot

Spring Boot 应用程序的任务是每隔几分钟更新一次远程集成 API。该应用程序可以部署到测试或生产环境,应用程序被告知它应该通过“application.properties”标志查看的端点。POJO 正在使用 Jackson 进行序列化并推送到端点,其中 JsonProperty 注释包含要推送到的 API 的字段 ID。

IE

@JsonProperty("field_001)
private String name;

@JsonProperty("field_002)
private String address;
Run Code Online (Sandbox Code Playgroud)

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

@JsonProperty("field_005)
private String name;

@JsonProperty("field_006)
private String address;
Run Code Online (Sandbox Code Playgroud)

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

例如,

可能存在三个文件 application.properties、application-test.properties 和 application-prod.properties。除了基于“spring.profiles.active”设置的普通属性文件之外,Spring Boot 还可以读取测试或产品属性。

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

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

@JsonProperty(@Value("${property.file.reference.here})) 
Run Code Online (Sandbox Code Playgroud)

似乎不起作用。

小智 5

我很抱歉重新提出一个老问题,但我仍然找不到满意的答案。

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

首先扩展内省器

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
}
Run Code Online (Sandbox Code Playgroud)

ObjectMapper然后通过配置使用

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

例子:

public class DynamicTestClass {
    @JsonProperty("${dynamic.property.name}")
    private String dynamicPropertyName;
    //getters/setters
}
Run Code Online (Sandbox Code Playgroud)
@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\"}"
    }
}
Run Code Online (Sandbox Code Playgroud)

测试.属性

dynamic.property.name=overriddenName
Run Code Online (Sandbox Code Playgroud)

该解决方案是反向兼容的,因此您仍然可以在中使用常量值@JsonProperty