Compare commits

..

6 Commits

Author SHA1 Message Date
Sean Leary
896ce0fb74 Merge pull request #1046 from yuki-matsuhashi/master
Validate XML numeric character references before string construction
2026-03-26 11:52:49 -05:00
Yuki Matsuhashi
1877069780 Validate XML numeric character references before string construction 2026-03-24 04:22:50 +09:00
Sean Leary
b959027aa2 Merge pull request #1044 from yuki-matsuhashi/1043-ignore-static
Ignore static fields in JSONObject.fromJson()
2026-03-16 09:24:24 -05:00
Yuki Matsuhashi
039f331d7d Add comment for empty test constructor 2026-03-13 01:54:58 +09:00
Yuki Matsuhashi
94e340002b Ignore static fields in JSONObject.fromJson() 2026-03-13 01:23:59 +09:00
Sean Leary
6230128f59 Merge pull request #1041 from stleary/license-clarification
Enhance README with license clarification
2026-02-22 15:14:00 -06:00
6 changed files with 72 additions and 2 deletions

View File

@@ -3349,7 +3349,7 @@ public class JSONObject {
* of the given class. It supports basic data types including {@code int}, {@code double}, * of the given class. It supports basic data types including {@code int}, {@code double},
* {@code float}, {@code long}, and {@code boolean}, as well as their boxed counterparts. * {@code float}, {@code long}, and {@code boolean}, as well as their boxed counterparts.
* The target class must have a no-argument constructor, and its field names must match * The target class must have a no-argument constructor, and its field names must match
* the keys in the JSON string. * the keys in the JSON string. Static fields are ignored.
* *
* <p><strong>Note:</strong> Only classes that are explicitly supported and registered within * <p><strong>Note:</strong> Only classes that are explicitly supported and registered within
* the {@code JSONObject} context can be deserialized. If the provided class is not among those, * the {@code JSONObject} context can be deserialized. If the provided class is not among those,
@@ -3366,6 +3366,9 @@ public class JSONObject {
try { try {
T obj = clazz.getDeclaredConstructor().newInstance(); T obj = clazz.getDeclaredConstructor().newInstance();
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
field.setAccessible(true); field.setAccessible(true);
String fieldName = field.getName(); String fieldName = field.getName();
if (has(fieldName)) { if (has(fieldName)) {

View File

@@ -158,7 +158,7 @@ public class XML {
* @param cp code point to test * @param cp code point to test
* @return true if the code point is not valid for an XML * @return true if the code point is not valid for an XML
*/ */
private static boolean mustEscape(int cp) { static boolean mustEscape(int cp) {
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets /* Valid range from https://www.w3.org/TR/REC-xml/#charsets
* *
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

View File

@@ -167,6 +167,9 @@ public class XMLTokener extends JSONTokener {
int cp = (e.charAt(1) == 'x' || e.charAt(1) == 'X') int cp = (e.charAt(1) == 'x' || e.charAt(1) == 'X')
? parseHexEntity(e) ? parseHexEntity(e)
: parseDecimalEntity(e); : parseDecimalEntity(e);
if (XML.mustEscape(cp)) {
throw new JSONException("Invalid numeric character reference: &#" + e.substring(1) + ";");
}
return new String(new int[] {cp}, 0, 1); return new String(new int[] {cp}, 0, 1);
} }
Character knownEntity = entity.get(e); Character knownEntity = entity.get(e);

View File

@@ -66,6 +66,7 @@ import org.json.junit.data.CustomClassF;
import org.json.junit.data.CustomClassG; import org.json.junit.data.CustomClassG;
import org.json.junit.data.CustomClassH; import org.json.junit.data.CustomClassH;
import org.json.junit.data.CustomClassI; import org.json.junit.data.CustomClassI;
import org.json.junit.data.CustomClassJ;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.After; import org.junit.After;
import org.junit.Ignore; import org.junit.Ignore;
@@ -4232,4 +4233,21 @@ public class JSONObjectTest {
CustomClassI compareClassI = new CustomClassI(dataList); CustomClassI compareClassI = new CustomClassI(dataList);
assertEquals(customClassI.integerMap.toString(), compareClassI.integerMap.toString()); assertEquals(customClassI.integerMap.toString(), compareClassI.integerMap.toString());
} }
@Test
public void jsonObjectParseFromJson_9() {
JSONObject object = new JSONObject();
object.put("number", 12);
object.put("classState", "mutated");
String initialClassState = CustomClassJ.classState;
CustomClassJ.classState = "original";
try {
CustomClassJ customClassJ = object.fromJson(CustomClassJ.class);
assertEquals(12, customClassJ.number);
assertEquals("original", CustomClassJ.classState);
} finally {
CustomClassJ.classState = initialClassState;
}
}
} }

View File

@@ -1468,6 +1468,42 @@ public class XMLTest {
XML.toJSONObject(xmlStr); XML.toJSONObject(xmlStr);
} }
/**
* Tests that out-of-range hex entities throw JSONException rather than an uncaught runtime exception.
*/
@Test(expected = JSONException.class)
public void testOutOfRangeHexEntityThrowsJSONException() {
String xmlStr = "<a>&#x110000;</a>";
XML.toJSONObject(xmlStr);
}
/**
* Tests that out-of-range decimal entities throw JSONException rather than an uncaught runtime exception.
*/
@Test(expected = JSONException.class)
public void testOutOfRangeDecimalEntityThrowsJSONException() {
String xmlStr = "<a>&#1114112;</a>";
XML.toJSONObject(xmlStr);
}
/**
* Tests that surrogate code point entities throw JSONException.
*/
@Test(expected = JSONException.class)
public void testSurrogateHexEntityThrowsJSONException() {
String xmlStr = "<a>&#xD800;</a>";
XML.toJSONObject(xmlStr);
}
/**
* Tests that out-of-range numeric entities in attribute values throw JSONException.
*/
@Test(expected = JSONException.class)
public void testOutOfRangeHexEntityInAttributeThrowsJSONException() {
String xmlStr = "<a b=\"&#x110000;\"/>";
XML.toJSONObject(xmlStr);
}
/** /**
* Tests that valid decimal numeric entity &#65; works correctly. * Tests that valid decimal numeric entity &#65; works correctly.
* Should decode to character 'A'. * Should decode to character 'A'.

View File

@@ -0,0 +1,10 @@
package org.json.junit.data;
public class CustomClassJ {
public static String classState = "original";
public int number;
public CustomClassJ() {
// Required for JSONObject#fromJson(Class<T>) tests.
}
}