Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从JsonParser(Jackson Json)获取底层字符串_Java_Android_Json_Jackson_Inputstream - Fatal编程技术网

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

Java 如何从JsonParser(Jackson Json)获取底层字符串,java,android,json,jackson,inputstream,Java,Android,Json,Jackson,Inputstream,通过查看文档和源代码,我看不到一个明确的方法来做到这一点。我很好奇我是否遗漏了什么 假设我从服务器响应接收到InputStream。我从这个InputStream创建了一个JsonParser。服务器响应应该是包含有效JSON的文本,例如: {“iamValidJson”:“耶”} 但是,如果响应最终是无效的JSON或根本不是JSON,例如: 一些非JSON的文本 JsonParser最终将抛出一个异常。在本例中,我希望能够从JsonParser中提取底层无效文本“一些非JSON的文本”,以便将

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

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

{“iamValidJson”:“耶”}

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

一些非JSON的文本

JsonParser最终将抛出一个异常。在本例中,我希望能够从JsonParser中提取底层无效文本“
一些非JSON的文本”
,以便将其用于其他目的

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


有办法做到这一点吗?

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


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

您试图做的事情超出了Jackson的范围(如果不是所有其他Java JSON库的话,也是大多数)。您要做的是将输入流完全转换为字符串,然后尝试使用Jackson将该字符串转换为JSON对象。如果转换失败,则对中间字符串执行某些操作,否则将正常进行。下面是一个例子,为了方便起见,它使用了优秀的:

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
}

我曾经使用过一个自定义反序列化程序,但我希望使用默认的反序列化程序来完成大部分工作,然后使用相同的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;
    }
}
public类WalkStepDeserializer扩展StdDeserializer实现
可解析反序列化器{
//未显示构造函数、记录器和可解析反序列化器方法
@凌驾
公共MyObj反序列化(JsonParser jp,反序列化上下文ctxt)抛出IOException,
JsonProcessingException{
MyObj MyObj=null;
JsonLocation startLocation=jp.getCurrentLocation();
long charOffsetStart=startLocation.getCharOffset();
试一试{
myObj=(myObj)defaultDeserializer.deserialize(jp,ctxt);
}捕获(无法识别的属性异常e){
logger.info(例如getMessage());
}
JsonLocation endLocation=jp.getCurrentLocation();
long charOffsetEnd=endLocation.getCharOffset();
字符串jsonSubString=endLocation.getSourceRef().toString().substring((int)charOffsetStart-1,(int)charOffsetEnd);
logger.info(strWalkStep);
//特殊逻辑-使用JsonLocation.getSourceRef()获取并使用整个Json
//用于进一步处理的字符串
返回myObj;
}
}

关于在自定义反序列化程序中使用默认反序列化程序的信息迟了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,这就是我提出的解决方案

我编写了自己的JSONTStringDeserializer,如下所示:

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);
    }
}
    final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
    return treeNode.toString();
我最初遵循的建议是使用如下树节点:

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);
    }
}
    final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
    return treeNode.toString();

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

我们在
JsonDeserializer
中使用此方法,使用
org.geotools.geojson.geom.GeometryJSON
解析器解析
geojson
对象,因为它只是直接解析Json
字符串。“然而,这可能需要解析的JSON确实是有效的JSON”如果您将
内容类型设置为
application/JSON
,那么您确实应该发送JSON格式的内容。也许您可以将其更改为
{“textDescription”:“text”}
替换为“textDescription”“无论在您的特定情况下有什么意义。但是请注意,Jackson可以解析任何JSON值,它不限于JSON文本(即,仅数组或对象)。事实上,大多数解析器都可以,即使RFC理论上禁止这样做。仅供参考,带引号的字符串或普通数字,甚至常量值
true
false
null
都是有效的JSON。请注意,您可以要求
JsonParser
不要关闭底层输入流。我相信您关于它超出范围的说法是正确的。我只是希望有其他的解决方案,因为这样做会破坏使用流式解析器的性能优势。但是,您的解决方案确实有效。流解析程序假定传入流是有效的(它必须这样做,因为它在令牌推送模式下运行)。出于与您提到的相同的性能原因,它不会“缓存”已处理的内容,它只是检查是否有有效的令牌,如果有,则将其发送到链中的下一个处理程序。如果没有,它就会发出嘎嘎声。另一个解决方案是实现一个累积流,并将其链接到您使用的任何输入流上。不一定是干净的,但它可以减轻您对流媒体性能的担忧