diff --git a/src/main/java/org/json/JSONML.java b/src/main/java/org/json/JSONML.java index bde97a680..6ec997061 100644 --- a/src/main/java/org/json/JSONML.java +++ b/src/main/java/org/json/JSONML.java @@ -22,6 +22,33 @@ public class JSONML { public JSONML() { } + /** + * Safely cast parse result to JSONArray with proper type checking. + * @param result The result from parse() method + * @return JSONArray if result is a JSONArray + * @throws JSONException if result is not a JSONArray + */ + private static JSONArray toJSONArraySafe(Object result) throws JSONException { + if (result instanceof JSONArray) { + return (JSONArray) result; + } + throw new JSONException("Expected JSONArray but got " + + (result == null ? "null" : result.getClass().getSimpleName())); + } + + /** + * Safely cast parse result to JSONObject with proper type checking. + * @param result The result from parse() method + * @return JSONObject if result is a JSONObject + * @throws JSONException if result is not a JSONObject + */ + private static JSONObject toJSONObjectSafe(Object result) throws JSONException { + if (result instanceof JSONObject) { + return (JSONObject) result; + } + throw new JSONException("Expected JSONObject but got " + + (result == null ? "null" : result.getClass().getSimpleName())); + } /** * Parse XML values and store them in a JSONArray. @@ -276,7 +303,7 @@ private static Object parse( * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(String string) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0); + return toJSONArraySafe(parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0)); } @@ -298,7 +325,7 @@ public static JSONArray toJSONArray(String string) throws JSONException { * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings, 0); + return toJSONArraySafe(parse(new XMLTokener(string), true, null, keepStrings, 0)); } @@ -323,7 +350,7 @@ public static JSONArray toJSONArray(String string, boolean keepStrings) throws J * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(String string, JSONMLParserConfiguration config) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, config, 0); + return toJSONArraySafe(parse(new XMLTokener(string), true, null, config, 0)); } @@ -347,7 +374,7 @@ public static JSONArray toJSONArray(String string, JSONMLParserConfiguration con * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return (JSONArray)parse(x, true, null, config, 0); + return toJSONArraySafe(parse(x, true, null, config, 0)); } @@ -369,7 +396,7 @@ public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration conf * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONArray)parse(x, true, null, keepStrings, 0); + return toJSONArraySafe(parse(x, true, null, keepStrings, 0)); } @@ -386,7 +413,7 @@ public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JS * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return (JSONArray)parse(x, true, null, false, 0); + return toJSONArraySafe(parse(x, true, null, false, 0)); } @@ -404,7 +431,7 @@ public static JSONArray toJSONArray(XMLTokener x) throws JSONException { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(String string) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, false, 0); + return toJSONObjectSafe(parse(new XMLTokener(string), false, null, false, 0)); } @@ -424,7 +451,7 @@ public static JSONObject toJSONObject(String string) throws JSONException { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings, 0); + return toJSONObjectSafe(parse(new XMLTokener(string), false, null, keepStrings, 0)); } @@ -446,7 +473,7 @@ public static JSONObject toJSONObject(String string, boolean keepStrings) throws * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(String string, JSONMLParserConfiguration config) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, config, 0); + return toJSONObjectSafe(parse(new XMLTokener(string), false, null, config, 0)); } @@ -464,7 +491,7 @@ public static JSONObject toJSONObject(String string, JSONMLParserConfiguration c * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return (JSONObject)parse(x, false, null, false, 0); + return toJSONObjectSafe(parse(x, false, null, false, 0)); } @@ -484,7 +511,7 @@ public static JSONObject toJSONObject(XMLTokener x) throws JSONException { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONObject)parse(x, false, null, keepStrings, 0); + return toJSONObjectSafe(parse(x, false, null, keepStrings, 0)); } @@ -506,7 +533,7 @@ public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return (JSONObject)parse(x, false, null, config, 0); + return toJSONObjectSafe(parse(x, false, null, config, 0)); } diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 5a360dd59..93a6821d8 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -986,4 +986,70 @@ public void testToJSONObjectMaxNestingDepthWithValidFittingXML() { } } + /** + * Tests that malformed XML causing type mismatch throws JSONException. + * Previously threw ClassCastException when parse() returned String instead of JSONArray. + * Related to issue #1034 + */ + @Test(expected = JSONException.class) + public void testMalformedXMLThrowsJSONExceptionNotClassCast() { + // This malformed XML causes parse() to return wrong type + byte[] data = {0x3c, 0x0a, 0x2f, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, 0x3e, 0x42}; + String xmlStr = new String(data); + JSONML.toJSONArray(xmlStr); + } + + /** + * Tests that type mismatch in toJSONObject throws JSONException. + * Validates safe type casting in toJSONObject methods. + */ + @Test + public void testToJSONObjectTypeMismatch() { + // Create XML that would cause parse() to return wrong type + String xmlStr = "<\n/\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff>B"; + try { + JSONML.toJSONObject(xmlStr); + fail("Expected JSONException for type mismatch"); + } catch (ClassCastException e) { + fail("Should throw JSONException, not ClassCastException"); + } catch (JSONException e) { + // Expected - verify it's about type mismatch + assertTrue("Exception message should mention type error", + e.getMessage().contains("Expected") || e.getMessage().contains("got")); + } + } + + /** + * Tests that valid XML still works correctly after the fix. + * Ensures the type checking doesn't break normal operation. + */ + @Test + public void testValidXMLStillWorks() { + String xmlStr = "value"; + try { + JSONArray jsonArray = JSONML.toJSONArray(xmlStr); + assertNotNull("JSONArray should not be null", jsonArray); + assertEquals("root", jsonArray.getString(0)); + } catch (Exception e) { + fail("Valid XML should not throw exception: " + e.getMessage()); + } + } + + /** + * Tests that valid XML to JSONObject still works correctly. + */ + @Test + public void testValidXMLToJSONObjectStillWorks() { + String xmlStr = "content"; + try { + JSONObject jsonObject = JSONML.toJSONObject(xmlStr); + assertNotNull("JSONObject should not be null", jsonObject); + assertEquals("root", jsonObject.getString("tagName")); + } catch (Exception e) { + fail("Valid XML should not throw exception: " + e.getMessage()); + } + } + }