java 如何从 JsonParser (Jackson Json) 获取底层字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16825880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:05:54  来源:igfitidea点击:

How to get the underlying String from a JsonParser (Hymanson Json)

javaandroidjsonHymansoninputstream

提问by cottonBallPaws

Looking through the documentation and source code I don't see a clear way to do this. Curious if I'm missing something.

查看文档和源代码,我没有看到明确的方法来做到这一点。好奇我是否遗漏了什么。

Say I receive an InputStream from a server response. I create a JsonParser from this InputStream. It is expected that the server response is text containing valid JSON, such as:

假设我从服务器响应中收到 InputStream。我从这个 InputStream 创建了一个 JsonParser。预计服务器响应是包含有效 JSON 的文本,例如:

{"iamValidJson":"yay"}

{"iamValidJson":"yay"}

However, if the response ends up being invalid JSON or not JSON at all such as:

但是,如果响应最终是无效的 JSON 或根本不是 JSON,例如:

Some text that is not JSON

Some text that is not JSON

the JsonParser will eventually throw an exception. In this case, I would like to be able to extract the underlying invalid text "Some text that is not JSON" out of the JsonParser so it can be used for another purpose.

JsonParser 最终会抛出异常。在这种情况下,我希望能够Some text that is not JSON从 JsonParser 中提取底层无效文本“ ”,以便将其用于其他目的。

I cannot pull it out of the InputStream because it doesn't support resetting and the creation of the JsonParser consumes it.

我无法将其从 InputStream 中拉出,因为它不支持重置并且 JsonParser 的创建会消耗它。

Is there a way to do this?

有没有办法做到这一点?

回答by Shadow Man

If you have the JsonParserthen you can use jsonParser.readValueAsTree().toString().

如果你有,JsonParser那么你可以使用jsonParser.readValueAsTree().toString().

However, this likely requires that the JSON being parsed is indeed valid JSON.

但是,这可能需要解析的 JSON 确实是有效的 JSON。

回答by user2636014

I had a situation where I was using a custom deserializer, but I wanted the default deserializer to do most of the work, and then using the SAME json do some additional custom work. However, after the default deserializer does its work, the JsonParser object current location was beyond the json text I needed. So I had the same problem as you: how to get access to the underlying json string.

我遇到过使用自定义解串器的情况,但我希望默认解串器完成大部分工作,然后使用 SAME json 完成一些额外的自定义工作。但是,在默认反序列化器完成其工作后,JsonParser 对象的当前位置超出了我需要的 json 文本。所以我和你有同样的问题:如何访问底层的 json 字符串。

You can use JsonParser.getCurrentLocation.getSourceRef()to get access to the underlying json source. Use JsonParser.getCurrentLocation().getCharOffset()to find the current location in the json source.

您可以使用JsonParser.getCurrentLocation.getSourceRef()来访问底层 json 源。用于JsonParser.getCurrentLocation().getCharOffset()在 json 源中查找当前位置。

Here's the solution I used:

这是我使用的解决方案:

public class WalkStepDeserializer extends StdDeserializer<WalkStep> implements
    ResolvableDeserializer {

    // constructor, logger, and ResolvableDeserializer methods not shown

    @Override
    public MyObj deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
            JsonProcessingException {
        MyObj myObj = null;

        JsonLocation startLocation = jp.getCurrentLocation();
        long charOffsetStart = startLocation.getCharOffset();

        try {
            myObj = (MyObj) defaultDeserializer.deserialize(jp, ctxt);
        } catch (UnrecognizedPropertyException e) {
            logger.info(e.getMessage());
        }

        JsonLocation endLocation = jp.getCurrentLocation();
        long charOffsetEnd = endLocation.getCharOffset();
        String jsonSubString = endLocation.getSourceRef().toString().substring((int)charOffsetStart - 1, (int)charOffsetEnd);
        logger.info(strWalkStep);

        // Special logic - use JsonLocation.getSourceRef() to get and use the entire Json
        // string for further processing

        return myObj;
    }
}

And info about using a default deserializer in a custom deserializer is at How do I call the default deserializer from a custom deserializer in Hymanson

有关在自定义解串器中使用默认解串器的信息位于如何从 Hymanson 中的自定义解串器调用默认解串器

回答by adbar

5 year late, but this was my solution:

晚了 5 年,但这是我的解决方案:

I converted the jsonParser to string

我将 jsonParser 转换为字符串

String requestString = jsonParser.readValueAsTree().toString();

Then I converted that string into a JsonParser

然后我将该字符串转换为 JsonParser

JsonFactory factory = new JsonFactory();
JsonParser parser  = factory.createParser(requestString);

Then I iterated through my parser

然后我遍历我的解析器

ObjectMapper objectMapper = new ObjectMapper();
while(!parser.isClosed()){
    JsonToken jsonToken = parser.nextToken();
    if(JsonToken.FIELD_NAME.equals(jsonToken)){
        String currentName = parser.getCurrentName();
        parser.nextToken();
        switch (currentName) {
            case "someObject":
                Object someObject = objectMapper.readValue(parser, Object.class)
                //validate someObject
                break;
        }
 }

I needed to save the original json string for logging purposes, which is why I did this in the first place. Was a headache to find out, but finally did it and I hope i'm helping someone out :)

我需要保存原始 json 字符串以用于日志记录,这就是我首先这样做的原因。很头疼,但终于做到了,我希望我能帮助别人:)

回答by Leon Bedeker

Building my own Deserialiser in which I wanted to deserialise a specific field as text i.s.o. a proper DTO, this is the solution I came up with.

构建我自己的反序列化器,其中我想将特定字段反序列化为 text iso 一个适当的 DTO,这是我想出的解决方案。

I wrote my own JsonToStringDeserializer like this:

我像这样编写了自己的 JsonToStringDeserializer:

import com.fasterxml.Hymanson.core.JsonParser;
import com.fasterxml.Hymanson.core.TreeNode;
import com.fasterxml.Hymanson.databind.DeserializationContext;
import com.fasterxml.Hymanson.databind.JsonDeserializer;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringEscapeUtils;

import java.io.IOException;

/**
 * Deserialiser to deserialise any Json content to a String.
 */
@NoArgsConstructor
public class JsonToStringDeserializer extends JsonDeserializer<String> {


    /**
     * Deserialise a Json attribute that is a fully fledged Json object, into a {@link String}.
     * @param jsonParser Parsed used for reading JSON content
     * @param context Context that can be used to access information about this deserialization activity.
     * @return The deserialized value as a {@link String}.
     * @throws IOException
     */
    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {

        final TreeNode node = jsonParser.getCodec().readTree(jsonParser);

        final String unescapedString = StringEscapeUtils.unescapeJava(node.toString());
        return unescapedString.substring(1, unescapedString.length()-1);
    }
}

Annotate the field you want to deserialize like this:

像这样注释要反序列化的字段:

@JsonDeserialize(using = JsonToStringDeserializer.class)

I initially followed advice that said to use a TreeNode like this:

我最初遵循的建议是使用像这样的 TreeNode:

    final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
    return treeNode.toString();

But then you get a Json String that contains escape characters.

但是你会得到一个包含转义字符的 Json 字符串。

回答by Perception

What you are trying to do is outside the scope of Hymanson (and most, if not all other Java JSON libraries out there). What you want to do is fully consume the input stream into a string, then attempt to convert that string to a JSON object using Hymanson. If the conversion fails then do something with the intermediate string, else proceed normally. Here's an example, which utilizes the excellent Apache Commons IO library, for convenience:

您正在尝试做的超出 Hymanson 的范围(以及大多数,如果不是所有其他 Java JSON 库)。您想要做的是将输入流完全消耗为字符串,然后尝试使用 Hymanson 将该字符串转换为 JSON 对象。如果转换失败,则对中间字符串做一些事情,否则继续正常进行。为方便起见,这里有一个示例,它利用了优秀的Apache Commons IO 库

final InputStream stream ; // Your stream here

final String json = IOUtils.toString(stream);
try {
    final JsonNode node = new ObjectMapper().readTree(json);
    // Do something with JSON object here
} catch(final JsonProcessingException jpe) {
    // Do something with intermediate string here
}