Spring Boot应用程序的任务是每隔几分钟更新一次远程集成API。此应用程序可以部署到测试或prod环境,应用程序将通过" application.properties"通知应该查看的终点。旗。正在使用Jackson序列化POJO并将其推送到端点,其中JsonProperty注释包含要推送到的API的字段ID。
即
@JsonProperty("field_001)
private String name;
@JsonProperty("field_002)
private String address;
这些值的字段标签在测试端点上有所不同。因此,测试端点可能希望属性映射为
@JsonProperty("field_005)
private String name;
@JsonProperty("field_006)
private String address;
我希望能够利用Spring Boot原生支持基于配置文件的属性文件。从运行时读取外部属性文件中的JsonProperty注释值。
例如,
可能有三个文件application.properties,application-test.properties和application-prod.properties。 除了基于" spring.profiles.active"的vanilla属性文件之外,Spring Boot还可以读入test或prod属性。设置。
...- test.properties将包含测试服务器字段的常量值。并且......- prod.properties将包含prod服务器字段的常量值。
嵌套注释,例如Spring的@Value标记,如下所示:
@JsonProperty(@Value("${property.file.reference.here}))
似乎不起作用。
答案 0 :(得分:1)
我怀疑你可以在Jackson注释中使用Spring Expression Language(SpEL)来做这件事,就像你正在尝试的那样(有或没有@Value
注释)。
我会通过创建一个JsonSerializer<YourPojo>
和/或JsonDeserializer<YourPojo>
来接收您的SpEL表达式并使用提供的字段名称创建(或读取)。
//make me a spring managed bean!
public class PojoSerializer extends JsonSerializer<YourPojo> {
@Value("${property.file.reference.name")
private String nameField;
@Value("${property.file.reference.address")
private String addrField;
@Override
public void serialize(YourPojo pojo, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField(nameField, pojo.getName());
jgen.writeStringField(addrField, pojo.getAddress());
jgen.writeEndObject();
}
}
由于这是一个Spring托管bean,您需要将其插入Spring托管ObjectMapper
。
ObjectMapper mapper = //my ObjectMapper from spring
PojoSerializer pojoSerializer = //my PojoSerializer from spring
SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null));
module.addSerializer(YourPojo.class, pojoSerializer);
mapper.registerModule(module);
SpringBoot的AutoConfiguration可能不需要其中一些。我一般不知道SpringBoot会为其Jackson AutoConfiguration选择什么,但JsonSerializer
和JsonDeserializer
可能会在ApplicationContext
中自动注册。
答案 1 :(得分:1)
我为重提一个老问题深表歉意,但仍然找不到令人满意的答案。
这是我使用扩展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
}
然后将其与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);
}
}
示例:
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
该解决方案是向下兼容的,因此您仍可以在@JsonProperty
中使用常量值