杰克逊使用变量插值进行反序列化

3
1个回答

3
你可以注册一个基于默认设置的自定义字符串反序列化器,它会在反序列化后插值变量。
但是,正如评论中指出的那样,这对于文件和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,但如何在每个反序列化器类型(即Path)上应用转换?我认为我必须创建一个JsonParser来覆盖getTextgetValusAsString - Guillaume Lecroc
@gulecroc 很好的建议!我已经更新了我的答案。 - Alexey Gavrilov
听起来不错!我被覆盖JsonParser卡住了,不知道有JsonParserDelegate!对不起,声望不够,无法投票...所以+1。 - Guillaume Lecroc
@GuillaumeLecroc 我很高兴它能够正常工作!这实际上是一个好问题和(我希望)一个好答案,可能有助于其他人。我相信即使您声望不高,也应该能够接受答案。这里有一个关于此的链接:http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work - Alexey Gavrilov
如何将其与YAML结合使用?我尝试了各种方法来链接工厂/设置编解码器,但对Jackson并不是很熟悉。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接