当前位置: 首页 > 知识库问答 >
问题:

如何在从Jackson中的字符串构造JsonNode时更改其值

巫马庆
2023-03-14

我有一个JSON字符串,我想在使用Jackson库构造JsonNode时更改该值。例如:-

input: {"name":"xyz","price":"90.00"}
output:{"name":"xyz-3","price":90.90}

我创建了自己的JsonFactory,并通过了自己的解析器。但我只能更改键,不能更改与键相关的值。

代码:

private static ObjectMapper create() {
        ObjectMapper objectMapper = new ObjectMapper(new JsonFactory() {
            @Override
            protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException {
                return new MyParser(super._createParser(data, offset, len, ctxt));
            }

            @Override
            protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOException {
                return new MyParser(super._createParser(in, ctxt));
            }

            @Override
            protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException {
                return new MyParser(super._createParser(r, ctxt));
            }

            @Override
            protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt, boolean recyclable)
                    throws IOException {
                return new MyParser(super._createParser(data, offset, len, ctxt, recyclable));
            }
        });

private static final class MyParser extends JsonParserDelegate {

        private MyParser(JsonParser d) {
            super(d);
        }

        @Override
        public String getCurrentName() throws IOException, JsonParseException {
            ....
        }

        @Override
        public String getText() throws IOException, JsonParseException {
           ...
        }

        @Override
        public Object getCurrentValue() {
            ...
        }


        @Override
        public String getValueAsString() throws IOException {
            ...
        }

        @Override
        public String getValueAsString(String defaultValue) throws IOException {
            ...
        }
    }

下面是根据字符串构造JsonNode的代码。

mapper.readTree(jsonStr);

在这种情况下,当readTree方法被称为getMONtValuegetValueAsString方法不被调用时,所以我不能在创建JsonNode本身时更改值。json字符串也可以不同。基本上,我想从字符串构造一个JsonNode。所以绑定到特定的模式/bean不是一个好的选择。如何解决这个问题?TIA

添加版本2.7.4的更新代码:-

static class MyParser extends JsonParserDelegate {
        MyParser(final JsonParser delegate) {
            super(delegate);
        }

        @Override
        public String getText() throws IOException {
            final String text = super.getText();

            if ("name".equals(getCurrentName())) {
                return text + "-3";
            }

            return text;
        }

        @Override
        public JsonToken nextToken() throws IOException {
            if ("price".equals(getCurrentName())) {
                // Advance token anyway
                super.nextToken();
                return JsonToken.VALUE_NUMBER_FLOAT;
            }

            return super.nextToken();
        }

        @Override
        public int getCurrentTokenId() {
            try {
                if ("price".equals(getCurrentName())) {
                    return JsonTokenId.ID_NUMBER_FLOAT;
                }
            } catch (final IOException e) {
                //
            }

            return super.getCurrentTokenId();
        }

        @Override
        public NumberType getNumberType() throws IOException {
            if ("price".equals(getCurrentName())) {
                return NumberType.FLOAT;
            }

            return super.getNumberType();
        }

        @Override
        public float getFloatValue() throws IOException {
            return Float.parseFloat(getValueAsString("0")) + 0.09F;
        }

        @Override
        public double getDoubleValue() throws IOException {
            return Double.parseDouble(getValueAsString("0")) + 0.09D;
        }


    }

波姆。xml:-

         <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-yaml</artifactId>
            <version>2.8.7</version>
            <!--<scope>test</scope>-->
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.8.7</version>
        </dependency>

共有2个答案

冯开诚
2023-03-14

关于关注点的分离,您真的确定在解析的数据中混合解析和更改是一个好主意吗?

如果您仍然想这样做,您可以使用自定义解序列化器,并按照您想要的方式处理您想要的字段名和类型,例如:

class CustomDeserializer extends StdDeserializer<Entity> {
    public CustomDeserializer(Class<Entity> t) {
        super(t);
    }

    @Override
    public Entity deserialize(JsonParser jp, DeserializationContext dc) throws IOException {
        String name = null;
        float price = 0;

        JsonToken currentToken = null;
        while ((currentToken = jp.nextValue()) != null) {
            switch (currentToken) {
                case VALUE_STRING:
                    switch (jp.getCurrentName()) {
                        case "name":
                            name = jp.getText() + "-3"; // change this text to whatever you want;
                            break;
                        case "price":
                            price = Float.parseFloat(jp.getText()); // parse
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
        return new Entity(name, price);
    }
}

注册自定义反序列化程序后,它可以在任何需要的对象映射器上工作:

    @Test
    public void customDeserialization() throws IOException {
        // given
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Entity.class, new CustomDeserializer(Entity.class));
        mapper.registerModule(module);

        // when
        Entity entity = mapper.readValue("{\"name\":\"xyz\",\"price\":\"90.00\"}", Entity.class);

        // then
        assertThat(entity.getName()).isEqualTo("xyz-3");
        assertThat(entity.getPrice()).isEqualTo(90f);
    }
郎鹤龄
2023-03-14

编辑:2.7.*2.9.*.
2.9.*能够区分浮点

getDoubleValue()
getFloatValue()

而不是2.7.*只使用

getDoubleValue()

即使是ID\u NUMBER\u FLOAT代币
因此,您需要决定是否要保持复古兼容性。

您也可以覆盖两者,就像我在这里做的那样。

这就是定制MyParser

static class MyParser extends JsonParserDelegate {
    MyParser(final JsonParser delegate) {
        super(delegate);
    }

    @Override
    public String getText() throws IOException {
        final String text = super.getText();

        if ("name".equals(getCurrentName())) {
            return text + "-3";
        }

        return text;
    }

    @Override
    public JsonToken nextToken() throws IOException {
        if ("price".equals(getCurrentName())) {
            // Advance token anyway
            super.nextToken();
            return JsonToken.VALUE_NUMBER_FLOAT;
        }

        return super.nextToken();
    }

    @Override
    public int getCurrentTokenId() {
        try {
            if ("price".equals(getCurrentName())) {
                return JsonTokenId.ID_NUMBER_FLOAT;
            }
        } catch (final IOException e) {
            //
        }

        return super.getCurrentTokenId();
    }

    @Override
    public NumberType getNumberType() throws IOException {
        if ("price".equals(getCurrentName())) {
            return NumberType.FLOAT;
        }

        return super.getNumberType();
    }

    @Override
    public float getFloatValue() throws IOException {
        return Float.parseFloat(getValueAsString("0")) + 0.09F;
    }

    @Override
    public double getDoubleValue() throws IOException {
       return Double.parseDouble(getValueAsString("0")) + 0.09D;
    }
}

输出:{"name":"xyz-3","price": 90.09}

您的代码看起来很好,并且经过测试并正常工作;)

 类似资料:
  • 我有下面的班级结构。 问题1:方法将对象作为参数并返回字符串,它只是返回一个空字符串对象,而不是设置字符串的属性并返回它。为什么?如何返回对象的属性? 问题2:当map方法的参数名为时,它使用类中的属性生成实现,否则只生成空的对象。我很惊讶地发现mapstruct生成的不同实现也取决于参数名。有什么解释吗? 注意:对象在另一个对象中用作属性。在那里我需要上面提到的行为。现在我是这样管理的。@map

  • 问题内容: 它应该是如此简单,但是在尝试一个小时的尴尬之后,我只是找不到它。 我需要获取一个JSON字符串,例如,解析为。 给 问题答案: 理查兹的答案略有不同,但可以使用字符串,因此可以将其简化为:

  • 关于这里的问题 我们有两个字符串A和B,它们具有相同的超级字符集。我们需要更改这些字符串以获得两个相等的字符串。在每次移动中,我们可以执行以下操作之一: 1-交换字符串的两个连续字符 2-交换字符串的第一个字符和最后一个字符 可以在任一字符串上执行移动。为了获得两个相等的字符串,我们需要的最小移动次数是多少?输入格式和约束:输入的第一行和第二行包含两个字符串A和B。保证它们的字符超集相等。1个 看

  • 问题内容: 我有一个bse64encoded字符串,来自外部源(Android商店)的公钥,我需要使用它来验证签名内容。如何将字符串转换为java.security.PublicKey接口的实例。如果这有所作为,我使用Java 6。 密钥是(可能)使用标准的Java库而不是有弹性的城堡生成的(它来自远程团队,所以我不确定)。他们的示例代码说使用Security.generatePublicKey(

  • 我有一个.odt wordprocessing文件,要用libre office或Word处理,我需要用其他文本替换文本中的一串(20+)字符串。我知道.odt文件实际上是一个.zip文件,包含.xml文件,并且我需要访问content.xml。我是否将content.xml解压缩到一个流中,反序列化该流并使用LINQ或其他东西?或者有没有更简单的方法,使用一些现成的库?

  • 下面是一个名为“containers”的表的片段。 如何将“产品”列更改为“字符变化[]”,并将相应的修饰符更改为默认值“{}”::字符变化[]?本质上,我想将字符串转换为字符串数组。注意,“产品”列对字符数没有限制。 抛出以下错误 错误:“products”列不能转换为不同类型的字符[]