JsonSyntaxException in BatchResponseContent when batch response contains non-JSON body
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Anfängerfreundlichkeit
- 48/100
Rechercherichtung
Beginnen Sie in com.microsoft.graph.core.content.BatchResponseContent, insbesondere bei getBatchResponseContent an der Stelle des Stack-Traces und bei getResponseById. Reproduzieren Sie das Parsen mit den im Issue gezeigten Batch-Bodies in Plain-Text und HTML und verifizieren Sie anschließend, dass Response-Bodies, die nicht im JSON-Format vorliegen, keine JsonSyntaxException mehr verursachen und für die Verarbeitung verfügbar bleiben.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Describe the bug
When making a batch request using the Microsoft Graph Java SDK, the SDK fails to parse the batch response if one of the individual responses contains a plain text body instead of valid JSON.
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 149 path $.responses[1].body
See https://github.com/google/gson/blob/main/Troubleshooting.md#malformed-json
at com.google.gson.internal.Streams.parse(Streams.java:58) ~[gson-2.11.0.jar!/:na]
at com.google.gson.JsonParser.parseReader(JsonParser.java:146) ~[gson-2.11.0.jar!/:na]
at com.google.gson.JsonParser.parseReader(JsonParser.java:110) ~[gson-2.11.0.jar!/:na]
at com.microsoft.graph.core.content.BatchResponseContent.getBatchResponseContent(BatchResponseContent.java:168) ~[microsoft-graph-core-3.6.1.jar!/:na]
...
Caused by: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 149 path $.responses[1].body
The raw batch response returned by the API looks like this (simplified for clarity):
{
"responses": [
{
"id": "a063d4a4-XXXX-4433-8704-6b1252f7e864",
"status": 200,
"headers": {
"Cache-Control": "private",
"Content-Type": "application/json; odata.metadata=minimal; odata.streaming=true; IEEE754Compatible=false; charset=utf-8"
},
"body": {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('user%40domain.com')/events(id)",
"value": [
{
"@odata.etag": "W/\"a+n3FpwGr06xxxxxxxxxjmCBjQ==\"",
"id": "AAMkAGVlYjJjNGxxxxxxxABGAAAAAAAkmk-HOxjKRZmNlLfGqYjaBwBr6fcWnAavTpXG0aD="
}
]
}
},
{
"id": "5f956687-XXXX-4aa4-a726-dc6b9810db1e",
"status": 503,
"headers": {
"Cache-Control": "private"
},
"body": Authentication Concurrency Limit Reached
}
]
}
As you can see, the second response has a body field that is not valid JSON (Authentication Concurrency Limit Reached), which causes the SDK to throw a JsonSyntaxException when parsing.
There is also another variant that falls into the same error:
{
"responses": [
{
"id": "6ea85c49-XXXX-4116-9844-2b0cbbf52ea3",
"status": 503,
"headers": {
"Content-Type": "text/html; charset=us-ascii"
},
"body":<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Service Unavailable</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Application Request Queue Full</h2>
<hr><p>HTTP Error 503. The application request queue is full.</p>
</BODY></HTML>
}
]
}
Expected behavior
The SDK should be able to handle non-JSON response bodies gracefully in batch responses. For example:
- Return the raw string body when the response is not valid JSON.
- Or provide a way to detect and handle such cases without throwing a parsing exception.
How to reproduce
- Use the
GraphServiceClientto send multiple requests (20 request per batch) in parallel (+4 in parallel) usingGraphServiceClient().getBatchRequestBuilder().post() - When the API is under load, one of the requests may return a 503 Authentication Concurrency Limit Reached error.
- The batch response will then contain a body field with plain text instead of valid JSON.
- Attempting to parse the batch response with BatchResponseContent.getResponseById(...) will throw a JsonSyntaxException.
To see the raw API response add the following interceptor to the OkHttpClient
@Slf4j
public class RawResponseLoggingInterceptor implements Interceptor {
@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
ResponseBody responseBody = response.body();
if (responseBody != null) {
try {
MediaType contentType = responseBody.contentType();
String rawJson = responseBody.string();
log.info("[API] Raw JSON Response for URL [{}], Status [{}]: {}", request.url(), response.code(), rawJson);
ResponseBody newResponseBody = ResponseBody.create(rawJson, contentType);
return response.newBuilder().body(newResponseBody).build();
} catch (Exception e) {
log.error("[API] Error reading raw response body for URL [{}]", request.url(), e);
}
}
return response;
}
}
RawResponseLoggingInterceptor loggingInterceptor = new RawResponseLoggingInterceptor();
OkHttpClient customOkHttpClient = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build();
GraphServiceClient client = new GraphServiceClient(authProvider, customOkHttpClient);
SDK Version
6.51.0
Latest version known to work for scenario above?
No response
Known Workarounds
No response
Debug output
Click to expand log
```com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 149 path $.responses[0].body
See https://github.com/google/gson/blob/main/Troubleshooting.md#malformed-json
at com.google.gson.internal.Streams.parse(Streams.java:58) ~[gson-2.11.0.jar!/:na]
at com.google.gson.JsonParser.parseReader(JsonParser.java:146) ~[gson-2.11.0.jar!/:na]
at com.google.gson.JsonParser.parseReader(JsonParser.java:110) ~[gson-2.11.0.jar!/:na]
at com.microsoft.graph.core.content.BatchResponseContent.getBatchResponseContent(BatchResponseContent.java:168) ~[microsoft-graph-core-3.6.1.jar!/:na]
at com.microsoft.graph.core.content.BatchResponseContent.getResponseById(BatchResponseContent.java:94) ~[microsoft-graph-core-3.6.1.jar!/:na]
at java.base/java.util.HashMap.forEach(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) ~[spring-aop-6.2.6.jar!/:6.2.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.2.6.jar!/:6.2.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.2.6.jar!/:6.2.6]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:114) ~[spring-aop-6.2.6.jar!/:6.2.6]
at java.base/java.util.concurrent.FutureTask.run(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:na]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 149 path $.responses[0].body
See https://github.com/google/gson/blob/main/Troubleshooting.md#malformed-json
at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1754) ~[gson-2.11.0.jar!/:na]
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:574) ~[gson-2.11.0.jar!/:na]
at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:498) ~[gson-2.11.0.jar!/:na]
at com.google.gson.internal.bind.TypeAdapters$28.read(TypeAdapters.java:875) ~[gson-2.11.0.jar!/:na]
at com.google.gson.internal.bind.TypeAdapters$28.read(TypeAdapters.java:820) ~[gson-2.11.0.jar!/:na]
at com.google.gson.internal.Streams.parse(Streams.java:46) ~[gson-2.11.0.jar!/:na]
... 18 common frames omitted
</details>
### Configuration
- OS: Windows 11 Pro 24H2
- Architecture: x64
- JDK: OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9-LTS)
### Other information
_No response_
- Vorherrschende Sprache
- Java
- Sterne
- 444
- Forks
- 154
- Ø Merge
- 18 Std. 28 Min.
- Gemergte PRs (30 T.)
- 4
Beitragsleitfaden
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus microsoftgraph/msgraph-sdk-java
-
status:waiting-for-triage type:bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
microsoftgraph/msgraph-sdk-java#2610 ·
-
status:waiting-for-triage type:bug
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 55/100
microsoftgraph/msgraph-sdk-java#2656 ·
-
status:waiting-for-triage type:bug
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 38/100
microsoftgraph/msgraph-sdk-java#2654 ·
-
status:waiting-for-triage
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 35/100
microsoftgraph/msgraph-sdk-java#2639 ·
-
status:waiting-for-triage type:bug
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 35/100
microsoftgraph/msgraph-sdk-java#2589 · 1 Kommentar ·
Alle Issues in microsoftgraph/msgraph-sdk-java
Ähnliche Issues
-
Bug Java Platform: Java
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
getsentry/sentry-java#6138 · 1 Kommentar ·
-
bug needs triage p2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
GoogleCloudPlatform/DataflowTemplates#4273 · 1 Kommentar ·
-
[LNG prod] Release 2.4.6 Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
-
[Studio][Bug] Bulk-deleting a full page of alert rules steps the page back while more rules remain Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
apache/rocketmq-dashboard#4654 · 1 Kommentar ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100