web-dev-qa-db-ja.com

JsonParser(Jackson Json)から基になる文字列を取得する方法

ドキュメントとソースコードを見ると、これを行う明確な方法がわかりません。私が何かを逃しているかどうか興味があります。

サーバーの応答からInputStreamを受け取ったとします。このInputStreamからJsonParserを作成します。サーバーの応答は、次のような有効なJSONを含むテキストであることが期待されます。

{"iamValidJson":"yay"}

ただし、応答が無効なJSONになるか、JSONではなくなる場合(次のように)。

Some text that is not JSON

jsonParserは最終的に例外をスローします。この場合、JsonParserから基になる無効なテキスト「Some text that is not JSON」を抽出して、別の目的に使用できるようにしたいと思います。

リセットをサポートしておらず、JsonParserの作成で消費されるため、InputStreamから引き出すことができません。

これを行う方法はありますか?

18
cottonBallPaws

JsonParserがある場合は、jsonParser.readValueAsTree().toString()を使用できます。

ただし、これには、解析されるJSONが実際に有効なJSONであることが必要になる可能性があります。

18
Shadow Man

カスタムデシリアライザーを使用している状況がありましたが、デフォルトのデシリアライザーでほとんどの作業を実行してから、同じ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;
    }
}

また、カスタムデシリアライザーでデフォルトのデシリアライザーを使用する方法については、 ジャクソンのカスタムデシリアライザーからデフォルトのデシリアライザーを呼び出すにはどうすればよいですか

5
user2636014

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文字列を保存する必要があったため、最初にこれを実行しました。見つけるのは頭痛の種でしたが、ついにそれをやりました。誰かを助けてくれることを願っています:)

3
adbar

あなたがやろうとしていることは、ジャクソンの範囲外です(そして、他のすべてではないにしても、ほとんどのJava JSONライブラリがあります)。あなたがしたいのは、入力ストリームを文字列に完全に消費することです。 、次に、Jacksonを使用してその文字列を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
}
2
Perception

特定のフィールドをテキスト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文字列を取得します。

2
Leon Bedeker