ドキュメントとソースコードを見ると、これを行う明確な方法がわかりません。私が何かを逃しているかどうか興味があります。
サーバーの応答からInputStreamを受け取ったとします。このInputStreamからJsonParserを作成します。サーバーの応答は、次のような有効なJSONを含むテキストであることが期待されます。
{"iamValidJson":"yay"}
ただし、応答が無効なJSONになるか、JSONではなくなる場合(次のように)。
Some text that is not JSON
jsonParserは最終的に例外をスローします。この場合、JsonParserから基になる無効なテキスト「Some text that is not JSON
」を抽出して、別の目的に使用できるようにしたいと思います。
リセットをサポートしておらず、JsonParserの作成で消費されるため、InputStreamから引き出すことができません。
これを行う方法はありますか?
JsonParser
がある場合は、jsonParser.readValueAsTree().toString()
を使用できます。
ただし、これには、解析されるJSONが実際に有効なJSONであることが必要になる可能性があります。
カスタムデシリアライザーを使用している状況がありましたが、デフォルトのデシリアライザーでほとんどの作業を実行してから、同じ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年遅れましたが、これが私の解決策でした。
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文字列を保存する必要があったため、最初にこれを実行しました。見つけるのは頭痛の種でしたが、ついにそれをやりました。誰かを助けてくれることを願っています:)
あなたがやろうとしていることは、ジャクソンの範囲外です(そして、他のすべてではないにしても、ほとんどの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
}
特定のフィールドをテキスト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文字列を取得します。