Skip to content

Commit d092d09

Browse files
authored
Merge pull request #1037 from OwenSanzas/fix-jsonml-classcast
Fix ClassCastException in JSONML.toJSONArray and toJSONObject
2 parents e635f40 + 0737e04 commit d092d09

File tree

2 files changed

+105
-12
lines changed

2 files changed

+105
-12
lines changed

src/main/java/org/json/JSONML.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,33 @@ public class JSONML {
2222
public JSONML() {
2323
}
2424

25+
/**
26+
* Safely cast parse result to JSONArray with proper type checking.
27+
* @param result The result from parse() method
28+
* @return JSONArray if result is a JSONArray
29+
* @throws JSONException if result is not a JSONArray
30+
*/
31+
private static JSONArray toJSONArraySafe(Object result) throws JSONException {
32+
if (result instanceof JSONArray) {
33+
return (JSONArray) result;
34+
}
35+
throw new JSONException("Expected JSONArray but got " +
36+
(result == null ? "null" : result.getClass().getSimpleName()));
37+
}
38+
39+
/**
40+
* Safely cast parse result to JSONObject with proper type checking.
41+
* @param result The result from parse() method
42+
* @return JSONObject if result is a JSONObject
43+
* @throws JSONException if result is not a JSONObject
44+
*/
45+
private static JSONObject toJSONObjectSafe(Object result) throws JSONException {
46+
if (result instanceof JSONObject) {
47+
return (JSONObject) result;
48+
}
49+
throw new JSONException("Expected JSONObject but got " +
50+
(result == null ? "null" : result.getClass().getSimpleName()));
51+
}
2552

2653
/**
2754
* Parse XML values and store them in a JSONArray.
@@ -276,7 +303,7 @@ private static Object parse(
276303
* @throws JSONException Thrown on error converting to a JSONArray
277304
*/
278305
public static JSONArray toJSONArray(String string) throws JSONException {
279-
return (JSONArray)parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0);
306+
return toJSONArraySafe(parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0));
280307
}
281308

282309

@@ -298,7 +325,7 @@ public static JSONArray toJSONArray(String string) throws JSONException {
298325
* @throws JSONException Thrown on error converting to a JSONArray
299326
*/
300327
public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
301-
return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings, 0);
328+
return toJSONArraySafe(parse(new XMLTokener(string), true, null, keepStrings, 0));
302329
}
303330

304331

@@ -323,7 +350,7 @@ public static JSONArray toJSONArray(String string, boolean keepStrings) throws J
323350
* @throws JSONException Thrown on error converting to a JSONArray
324351
*/
325352
public static JSONArray toJSONArray(String string, JSONMLParserConfiguration config) throws JSONException {
326-
return (JSONArray)parse(new XMLTokener(string), true, null, config, 0);
353+
return toJSONArraySafe(parse(new XMLTokener(string), true, null, config, 0));
327354
}
328355

329356

@@ -347,7 +374,7 @@ public static JSONArray toJSONArray(String string, JSONMLParserConfiguration con
347374
* @throws JSONException Thrown on error converting to a JSONArray
348375
*/
349376
public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration config) throws JSONException {
350-
return (JSONArray)parse(x, true, null, config, 0);
377+
return toJSONArraySafe(parse(x, true, null, config, 0));
351378
}
352379

353380

@@ -369,7 +396,7 @@ public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration conf
369396
* @throws JSONException Thrown on error converting to a JSONArray
370397
*/
371398
public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
372-
return (JSONArray)parse(x, true, null, keepStrings, 0);
399+
return toJSONArraySafe(parse(x, true, null, keepStrings, 0));
373400
}
374401

375402

@@ -386,7 +413,7 @@ public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JS
386413
* @throws JSONException Thrown on error converting to a JSONArray
387414
*/
388415
public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
389-
return (JSONArray)parse(x, true, null, false, 0);
416+
return toJSONArraySafe(parse(x, true, null, false, 0));
390417
}
391418

392419

@@ -404,7 +431,7 @@ public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
404431
* @throws JSONException Thrown on error converting to a JSONObject
405432
*/
406433
public static JSONObject toJSONObject(String string) throws JSONException {
407-
return (JSONObject)parse(new XMLTokener(string), false, null, false, 0);
434+
return toJSONObjectSafe(parse(new XMLTokener(string), false, null, false, 0));
408435
}
409436

410437

@@ -424,7 +451,7 @@ public static JSONObject toJSONObject(String string) throws JSONException {
424451
* @throws JSONException Thrown on error converting to a JSONObject
425452
*/
426453
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
427-
return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings, 0);
454+
return toJSONObjectSafe(parse(new XMLTokener(string), false, null, keepStrings, 0));
428455
}
429456

430457

@@ -446,7 +473,7 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws
446473
* @throws JSONException Thrown on error converting to a JSONObject
447474
*/
448475
public static JSONObject toJSONObject(String string, JSONMLParserConfiguration config) throws JSONException {
449-
return (JSONObject)parse(new XMLTokener(string), false, null, config, 0);
476+
return toJSONObjectSafe(parse(new XMLTokener(string), false, null, config, 0));
450477
}
451478

452479

@@ -464,7 +491,7 @@ public static JSONObject toJSONObject(String string, JSONMLParserConfiguration c
464491
* @throws JSONException Thrown on error converting to a JSONObject
465492
*/
466493
public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
467-
return (JSONObject)parse(x, false, null, false, 0);
494+
return toJSONObjectSafe(parse(x, false, null, false, 0));
468495
}
469496

470497

@@ -484,7 +511,7 @@ public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
484511
* @throws JSONException Thrown on error converting to a JSONObject
485512
*/
486513
public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
487-
return (JSONObject)parse(x, false, null, keepStrings, 0);
514+
return toJSONObjectSafe(parse(x, false, null, keepStrings, 0));
488515
}
489516

490517

@@ -506,7 +533,7 @@ public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws
506533
* @throws JSONException Thrown on error converting to a JSONObject
507534
*/
508535
public static JSONObject toJSONObject(XMLTokener x, JSONMLParserConfiguration config) throws JSONException {
509-
return (JSONObject)parse(x, false, null, config, 0);
536+
return toJSONObjectSafe(parse(x, false, null, config, 0));
510537
}
511538

512539

src/test/java/org/json/junit/JSONMLTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,4 +986,70 @@ public void testToJSONObjectMaxNestingDepthWithValidFittingXML() {
986986
}
987987
}
988988

989+
/**
990+
* Tests that malformed XML causing type mismatch throws JSONException.
991+
* Previously threw ClassCastException when parse() returned String instead of JSONArray.
992+
* Related to issue #1034
993+
*/
994+
@Test(expected = JSONException.class)
995+
public void testMalformedXMLThrowsJSONExceptionNotClassCast() {
996+
// This malformed XML causes parse() to return wrong type
997+
byte[] data = {0x3c, 0x0a, 0x2f, (byte)0xff, (byte)0xff, (byte)0xff,
998+
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
999+
(byte)0xff, 0x3e, 0x42};
1000+
String xmlStr = new String(data);
1001+
JSONML.toJSONArray(xmlStr);
1002+
}
1003+
1004+
/**
1005+
* Tests that type mismatch in toJSONObject throws JSONException.
1006+
* Validates safe type casting in toJSONObject methods.
1007+
*/
1008+
@Test
1009+
public void testToJSONObjectTypeMismatch() {
1010+
// Create XML that would cause parse() to return wrong type
1011+
String xmlStr = "<\n/\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff>B";
1012+
try {
1013+
JSONML.toJSONObject(xmlStr);
1014+
fail("Expected JSONException for type mismatch");
1015+
} catch (ClassCastException e) {
1016+
fail("Should throw JSONException, not ClassCastException");
1017+
} catch (JSONException e) {
1018+
// Expected - verify it's about type mismatch
1019+
assertTrue("Exception message should mention type error",
1020+
e.getMessage().contains("Expected") || e.getMessage().contains("got"));
1021+
}
1022+
}
1023+
1024+
/**
1025+
* Tests that valid XML still works correctly after the fix.
1026+
* Ensures the type checking doesn't break normal operation.
1027+
*/
1028+
@Test
1029+
public void testValidXMLStillWorks() {
1030+
String xmlStr = "<root><item>value</item></root>";
1031+
try {
1032+
JSONArray jsonArray = JSONML.toJSONArray(xmlStr);
1033+
assertNotNull("JSONArray should not be null", jsonArray);
1034+
assertEquals("root", jsonArray.getString(0));
1035+
} catch (Exception e) {
1036+
fail("Valid XML should not throw exception: " + e.getMessage());
1037+
}
1038+
}
1039+
1040+
/**
1041+
* Tests that valid XML to JSONObject still works correctly.
1042+
*/
1043+
@Test
1044+
public void testValidXMLToJSONObjectStillWorks() {
1045+
String xmlStr = "<root attr=\"value\"><item>content</item></root>";
1046+
try {
1047+
JSONObject jsonObject = JSONML.toJSONObject(xmlStr);
1048+
assertNotNull("JSONObject should not be null", jsonObject);
1049+
assertEquals("root", jsonObject.getString("tagName"));
1050+
} catch (Exception e) {
1051+
fail("Valid XML should not throw exception: " + e.getMessage());
1052+
}
1053+
}
1054+
9891055
}

0 commit comments

Comments
 (0)