浏览文档和源代码,我没有看到明确的方法来做到这一点。好奇,如果我错过了什么。
假设我从服务器响应中收到一个InputStream。我从这个InputStream创建一个JsonParser。预计服务器响应是包含有效JSON的文本,例如:
{"iamValidJson":"yay"}
但是,如果响应最终是无效的JSON或根本不是JSON,例如:
Some text that is not JSON
JsonParser最终会抛出异常。在这种情况下,我希望能够从JsonParser中提取底层的无效文本“Some text that is not JSON
”,以便它可以用于其他目的。
我无法将其从InputStream中拉出来,因为它不支持重置,并且JsonParser的创建会消耗它。
有没有办法做到这一点?
如果你有JsonParser
那么你可以使用jsonParser.readValueAsTree().toString()
。
但是,这可能要求解析的JSON确实是有效的JSON。
我有一个使用自定义反序列化器的情况,但我希望默认的反序列化器完成大部分工作,然后使用SAME json做一些额外的自定义工作。但是,在默认的反序列化器完成其工作后,JsonParser对象的当前位置超出了我需要的json文本。所以我遇到了和你一样的问题:如何访问底层的json字符串。
您可以使用JsonParser.getCurrentLocation.getSourceRef()
来访问底层的json源。使用JsonParser.getCurrentLocation().getCharOffset()
查找json源中的当前位置。
这是我使用的解决方案:
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;
}
}
有关在自定义反序列化器中使用默认反序列化器的信息,请访问How do I call the default deserializer from a custom deserializer in Jackson
你要做的是超出Jackson的范围(大多数,如果不是所有其他Java JSON库那么)。您要做的是将输入流完全消耗为字符串,然后尝试使用Jackson将该字符串转换为JSON对象。如果转换失败,则使用中间字符串执行某些操作,否则正常进行。这是一个例子,它使用了优秀的Apache Commons IO library,方便:
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
}
晚了5年,但这是我的解决方案:
我将jsonParser转换为字符串
String requestString = jsonParser.readValueAsTree().toString();
然后我将该字符串转换为JsonParser
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(requestString);
然后我遍历我的解析器
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;
}
}
我需要保存原始的json字符串以便进行日志记录,这就是为什么我首先要这样做的原因。很难找到,但终于做到了,我希望我帮助别人:)
构建我自己的反序列化器,我想在其中将特定字段反序列化为文本i.s.o.一个合适的DTO,这是我提出的解决方案。
我写了这样的自己的JsonToStringDeserializer:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.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);
}
}
注释要反序列化的字段,如下所示:
@JsonDeserialize(using = JsonToStringDeserializer.class)
我最初遵循的建议说使用这样的TreeNode:
final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
return treeNode.toString();
但是你得到一个包含转义字符的Json字符串。