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
How to get the underlying String from a JsonParser (Hymanson Json)
提问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 JsonParser
then 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
}