【问题标题】:Jackson deserialize with variable interpolationJackson 使用可变插值反序列化
【发布时间】:2014-12-15 14:21:18
【问题描述】:

如何自定义 Jackson 以反序列化包含 ${token} 的值?

这是我想从Apache Commons Configuration variable interpolation 添加的功能示例:

{
    "file" = "${sys:user.home}/path/to/my_file"
}

【问题讨论】:

    标签: java json jackson token interpolation


    【解决方案1】:

    您可以根据默认值注册custom string deserialiser,它将在反序列化后插入变量。

    但是,正如 cmets 中所指出的,这不适用于非字符串类型,例如文件和 URL。更好的办法是通过传递自定义的JsonFactory 来覆盖JsonParsergetText()getValueAsString() 方法。

    这是一个例子:

    public class JacksonInterpolateString {
        static final String JSON = "{ \"file\":\"${sys:user.home}/path/to/my_file\" }";
    
        public static class Bean {
            public File file;
    
            @Override
            public String toString() {
                return file.toString();
            }
        }
    
        private static class MyJsonParser extends JsonParserDelegate {
    
            public MyJsonParser(final JsonParser d) {
                super(d);
            }
    
            @Override
            public String getText() throws IOException {
                final String value = super.getText();
                if (value != null) {
                    return interpolateString(value);
                }
                return value;
            }
    
            @Override
            public String getValueAsString() throws IOException {
                return getValueAsString(null);
            }
    
            @Override
            public String getValueAsString(final String defaultValue) throws IOException {
                final String value = super.getValueAsString(defaultValue);
                if (value != null) {
                    return interpolateString(value);
                }
                return null;
            }
        }
    
        private static class MyMappingJsonFactory extends MappingJsonFactory {
            @Override
            protected JsonParser _createParser(
                    final char[] data,
                    final int offset,
                    final int len,
                    final IOContext ctxt,
                    final boolean recyclable)
                    throws IOException {
                return new MyJsonParser(super._createParser(data, offset, len, ctxt, recyclable));
            }
    
            @Override
            protected JsonParser _createParser(final Reader r, final IOContext ctxt)
                    throws IOException {
                return new MyJsonParser(super._createParser(r, ctxt));
            }
    
        }
    
        private static String interpolateString(final String value) {
            return value.replace("${sys:user.home}", "/home/user");
        }
    
        public static void main(String[] args) throws IOException {
            final JsonFactory factory = new MyMappingJsonFactory();
            final ObjectMapper mapper = new ObjectMapper(factory);
            System.out.println(mapper.readValue(JSON, Map.class));
            System.out.println(mapper.readValue(JSON, Bean.class));
        }
    
    }
    

    输出:

    {file=/home/user/path/to/my_file}
    /home/user/path/to/my_file
    

    【讨论】:

    • 他的解决方案仅在我想反序列化 String 时才有效,但是如何对每个反序列化器类型(即路径)应用转换?我想我必须创建一个 JsonParser 来覆盖 getTextgetValusAsString?
    • @gulecroc 好点!我已根据您的建议更新了我的答案。
    • 听起来不错!我被覆盖JsonParser 卡住了,不知道JsonParserDelegate!很抱歉没有足够的声誉来投票......所以+1
    • @GuillaumeLecroc 我很高兴它有效!这实际上是一个很好的问题,并且(我希望)一个很好的答案,它可能会帮助其他人。我相信即使你没有什么名声,你也应该能够接受这个答案。这是一个链接:meta.stackexchange.com/questions/5234/…
    猜你喜欢
    • 2018-08-14
    • 1970-01-01
    • 2012-07-24
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    相关资源
    最近更新 更多