繁体   English   中英

如何从Jackson @JsonCreator构造函数访问Spring Boot环境变量

[英]How can I access a Spring Boot environment variable from a Jackson @JsonCreator constructor

我有一个不变的模型类,可以由Jackson使用@JsonCreator注释的构造函数实例化。 这些属性之一是可选的,我想基于application.yml的变量创建一个动态默认值,以替换下面的固定值30。

public class DataRequest {
    private final List<String> fields;
    private final int sessionTimeoutSecs;

    @JsonCreator
    public DataRequest(@JsonProperty("fields") final List<String> fields,
                       @JsonProperty("sessionTimeoutSecs") final Integer sessionTimeoutSecs) {
        this.fields = fields;
        this.sessionTimeoutSecs = MoreObjects.firstNonNull(sessionTimeoutSecs, 30);
    }
}

我尝试添加一个附加的构造函数参数@Value("${default-session-timeout-secs}") final int defaultSessionTimeout但是在尝试映射时会导致MessageConversionException

您可以通过桥接属性并使用@JacksonInject 此注释与对象映射器配合使用良好。 我跳过了有关如何在代码中将spring桥接到jackson的部分,但是给了您一个简单的ObjectMapper示例。 参见以下代码:

package de.pandaadb.jackson;

import java.io.IOException;

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DataModel {

    private String test;
    private String optionalValue;

    @JsonCreator
    public DataModel(@JsonProperty("test") String test, @JacksonInject("opt") @JsonProperty(value= "opt", required=false)String opt) {
        this.optionalValue = opt;
        this.test = test;
    }

    @Override
    public String toString() {
        return "test=" + test + " optional=" + optionalValue;
    }


    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        InjectableValues.Std std = new InjectableValues.Std();
        std.addValue("opt", "alternative");

        String withOptional = "{\"test\" : \"hello\" ,    \"opt\" : \"optss\"}";
        String withoutOptional = "{\"test\" : \"hello\"}";

        mapper.setInjectableValues(std);

        System.out.println(mapper.readValue(withOptional, DataModel.class));
        System.out.println(mapper.readValue(withoutOptional, DataModel.class));
    }
}

此代码打印:

test=hello optional=optss
test=hello optional=alternative

一些注意事项:

  1. 除了属性之外,构造函数还使用构造函数中的JacksonInject批注。 这将首先注入配置的值,可选地使用来自输入的json值覆盖它。

  2. 正在向ObjectMapper提供与我们具有的注释匹配的属性

第二部分是最重要的。

至于使用spring进行此工作,方法是在您的配置中包含以下代码:

@Configuration
public class ObjectMapperConfiguration {

    ObjectMapper mapper(@Value("${my.test.string}") String test) {
        ObjectMapper mapper = new ObjectMapper();
        InjectableValues.Std std = new InjectableValues.Std();
        std.addValue("my.test.string", "test");
        mapper.setInjectableValues(std);
        return mapper;
    }
}

另外,您也可以注入ALL属性,并将其反馈给对象映射器,以免不必对每个新属性进行扩展。

希望对您有所帮助,

一些更多的阅读材料在这里: https : //www.concretepage.com/jackson-api/jackson-jacksoninject-example#ObjectMapper

最新编辑:如何仅使用1个构造函数参数,让jackson自己处理覆盖

-阿图尔

您可以通过使用两个帮助程序类来实现。

第一个是ContextHolder ,它使您可以从Spring托管的bean外部访问Spring的ApplicationContext:

@Component
public class ContextHolder implements ApplicationContextAware {

    public static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ContextHolder.applicationContext = applicationContext;
    }
}

第二个是DefaultTimeoutWrapper ,其中包含默认超时值:

@Component
public class DefaultTimeoutWrapper {
    @Value("${default-session-timeout-secs}")
    private int defaultTimeout;

    public int getDefaultTimeout() {
        return defaultTimeout;
    }
}

然后,您需要更改DataRequest类以使用它们,如下所示:

public class DataRequest {
    private final List<String> fields;
    private final int sessionTimeoutSecs;

    @JsonCreator
    public DataRequest(@JsonProperty("fields") final List<String> fields,
                       @JsonProperty("sessionTimeoutSecs") final Integer sessionTimeoutSecs) {
        DefaultTimeoutWrapper defaultTimeoutWrapper = ContextHolder.applicationContext.getBean(DefaultTimeoutWrapper.class);
        int defaultTimeout = defaultTimeoutWrapper.getDefaultTimeout();

        this.fields = fields;
        this.sessionTimeoutSecs = sessionTimeoutSecs != null ? sessionTimeoutSecs : defaultTimeout;
    }
}

请注意,在ContextHolder实例方法用于设置静态字段的值,通常认为这是不好的设计。

暂无
暂无

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

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