mirror of
https://github.com/stleary/JSON-java.git
synced 2025-08-04 03:45:35 -04:00
Compare commits
No commits in common. "master" and "20250517" have entirely different histories.
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@ -40,4 +40,4 @@ jobs:
|
|||||||
- run: "mvn clean compile -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true"
|
- run: "mvn clean compile -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true"
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v2
|
||||||
|
14
build.gradle
14
build.gradle
@ -3,10 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'eclipse'
|
apply plugin: 'eclipse'
|
||||||
apply plugin: 'jacoco'
|
// apply plugin: 'jacoco'
|
||||||
apply plugin: 'maven-publish'
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
// for now, publishing to maven is still a manual process
|
|
||||||
//plugins {
|
//plugins {
|
||||||
// id 'java'
|
// id 'java'
|
||||||
//id 'maven-publish'
|
//id 'maven-publish'
|
||||||
@ -20,17 +19,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To view the report open build/reports/jacoco/test/html/index.html
|
|
||||||
jacocoTestReport {
|
|
||||||
reports {
|
|
||||||
html.required = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
finalizedBy jacocoTestReport
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
testImplementation 'com.jayway.jsonpath:json-path:2.9.0'
|
testImplementation 'com.jayway.jsonpath:json-path:2.9.0'
|
||||||
|
@ -334,11 +334,13 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
*/
|
*/
|
||||||
public boolean getBoolean(int index) throws JSONException {
|
public boolean getBoolean(int index) throws JSONException {
|
||||||
Object object = this.get(index);
|
Object object = this.get(index);
|
||||||
if (Boolean.FALSE.equals(object)
|
if (object.equals(Boolean.FALSE)
|
||||||
|| (object instanceof String && "false".equalsIgnoreCase((String) object))) {
|
|| (object instanceof String && ((String) object)
|
||||||
|
.equalsIgnoreCase("false"))) {
|
||||||
return false;
|
return false;
|
||||||
} else if (Boolean.TRUE.equals(object)
|
} else if (object.equals(Boolean.TRUE)
|
||||||
|| (object instanceof String && "true".equalsIgnoreCase((String) object))) {
|
|| (object instanceof String && ((String) object)
|
||||||
|
.equalsIgnoreCase("true"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw wrongValueFormatException(index, "boolean", object, null);
|
throw wrongValueFormatException(index, "boolean", object, null);
|
||||||
|
@ -111,7 +111,7 @@ public class JSONML {
|
|||||||
}
|
}
|
||||||
} else if (c == '[') {
|
} else if (c == '[') {
|
||||||
token = x.nextToken();
|
token = x.nextToken();
|
||||||
if ("CDATA".equals(token) && x.next() == '[') {
|
if (token.equals("CDATA") && x.next() == '[') {
|
||||||
if (ja != null) {
|
if (ja != null) {
|
||||||
ja.put(x.nextCDATA());
|
ja.put(x.nextCDATA());
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,17 @@ public class JSONObject {
|
|||||||
*/
|
*/
|
||||||
private static final class Null {
|
private static final class Null {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There is only intended to be a single instance of the NULL object,
|
||||||
|
* so the clone method returns itself.
|
||||||
|
*
|
||||||
|
* @return NULL.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected final Object clone() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Null object is equal to the null value and to itself.
|
* A Null object is equal to the null value and to itself.
|
||||||
*
|
*
|
||||||
@ -169,7 +180,7 @@ public class JSONObject {
|
|||||||
for (int i = 0; i < names.length; i += 1) {
|
for (int i = 0; i < names.length; i += 1) {
|
||||||
try {
|
try {
|
||||||
this.putOnce(names[i], jo.opt(names[i]));
|
this.putOnce(names[i], jo.opt(names[i]));
|
||||||
} catch (Exception ignore) { // exception thrown for missing key
|
} catch (Exception ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,134 +211,79 @@ public class JSONObject {
|
|||||||
*/
|
*/
|
||||||
public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||||
this();
|
this();
|
||||||
|
char c;
|
||||||
|
String key;
|
||||||
|
|
||||||
boolean isInitial = x.getPrevious() == 0;
|
boolean isInitial = x.getPrevious() == 0;
|
||||||
|
|
||||||
if (x.nextClean() != '{') {
|
if (x.nextClean() != '{') {
|
||||||
throw x.syntaxError("A JSONObject text must begin with '{'");
|
throw x.syntaxError("A JSONObject text must begin with '{'");
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (parseJSONObject(x, jsonParserConfiguration, isInitial)) {
|
c = x.nextClean();
|
||||||
return;
|
switch (c) {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses entirety of JSON object
|
|
||||||
*
|
|
||||||
* @param jsonTokener Parses text as tokens
|
|
||||||
* @param jsonParserConfiguration Variable to pass parser custom configuration for json parsing.
|
|
||||||
* @param isInitial True if start of document, else false
|
|
||||||
* @return True if done building object, else false
|
|
||||||
*/
|
|
||||||
private boolean parseJSONObject(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) {
|
|
||||||
Object obj;
|
|
||||||
String key;
|
|
||||||
boolean doneParsing = false;
|
|
||||||
char c = jsonTokener.nextClean();
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 0:
|
case 0:
|
||||||
throw jsonTokener.syntaxError("A JSONObject text must end with '}'");
|
throw x.syntaxError("A JSONObject text must end with '}'");
|
||||||
case '}':
|
case '}':
|
||||||
if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != 0) {
|
if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) {
|
||||||
throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||||
}
|
}
|
||||||
return true;
|
return;
|
||||||
default:
|
default:
|
||||||
obj = jsonTokener.nextSimpleValue(c);
|
key = x.nextSimpleValue(c).toString();
|
||||||
key = obj.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
checkKeyForStrictMode(jsonTokener, jsonParserConfiguration, obj);
|
|
||||||
|
|
||||||
// The key is followed by ':'.
|
|
||||||
c = jsonTokener.nextClean();
|
|
||||||
if (c != ':') {
|
|
||||||
throw jsonTokener.syntaxError("Expected a ':' after a key");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use syntaxError(..) to include error location
|
|
||||||
if (key != null) {
|
|
||||||
// Check if key exists
|
|
||||||
boolean keyExists = this.opt(key) != null;
|
|
||||||
if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) {
|
|
||||||
throw jsonTokener.syntaxError("Duplicate key \"" + key + "\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object value = jsonTokener.nextValue();
|
// The key is followed by ':'.
|
||||||
// Only add value if non-null
|
|
||||||
if (value != null) {
|
c = x.nextClean();
|
||||||
this.put(key, value);
|
if (c != ':') {
|
||||||
|
throw x.syntaxError("Expected a ':' after a key");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Pairs are separated by ','.
|
// Use syntaxError(..) to include error location
|
||||||
if (parseEndOfKeyValuePair(jsonTokener, jsonParserConfiguration, isInitial)) {
|
|
||||||
doneParsing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return doneParsing;
|
if (key != null) {
|
||||||
}
|
// Check if key exists
|
||||||
|
boolean keyExists = this.opt(key) != null;
|
||||||
|
if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) {
|
||||||
|
throw x.syntaxError("Duplicate key \"" + key + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
Object value = x.nextValue();
|
||||||
* Checks for valid end of key:value pair
|
// Only add value if non-null
|
||||||
* @param jsonTokener Parses text as tokens
|
if (value != null) {
|
||||||
* @param jsonParserConfiguration Variable to pass parser custom configuration for json parsing.
|
this.put(key, value);
|
||||||
* @param isInitial True if end of JSON object, else false
|
}
|
||||||
* @return
|
}
|
||||||
*/
|
|
||||||
private static boolean parseEndOfKeyValuePair(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) {
|
// Pairs are separated by ','.
|
||||||
switch (jsonTokener.nextClean()) {
|
|
||||||
|
switch (x.nextClean()) {
|
||||||
case ';':
|
case ';':
|
||||||
// In strict mode semicolon is not a valid separator
|
// In strict mode semicolon is not a valid separator
|
||||||
if (jsonParserConfiguration.isStrictMode()) {
|
if (jsonParserConfiguration.isStrictMode()) {
|
||||||
throw jsonTokener.syntaxError("Strict mode error: Invalid character ';' found");
|
throw x.syntaxError("Strict mode error: Invalid character ';' found");
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case ',':
|
case ',':
|
||||||
if (jsonTokener.nextClean() == '}') {
|
if (x.nextClean() == '}') {
|
||||||
// trailing commas are not allowed in strict mode
|
// trailing commas are not allowed in strict mode
|
||||||
if (jsonParserConfiguration.isStrictMode()) {
|
if (jsonParserConfiguration.isStrictMode()) {
|
||||||
throw jsonTokener.syntaxError("Strict mode error: Expected another object element");
|
throw x.syntaxError("Strict mode error: Expected another object element");
|
||||||
}
|
}
|
||||||
// End of JSON object
|
return;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (jsonTokener.end()) {
|
if (x.end()) {
|
||||||
throw jsonTokener.syntaxError("A JSONObject text must end with '}'");
|
throw x.syntaxError("A JSONObject text must end with '}'");
|
||||||
}
|
}
|
||||||
jsonTokener.back();
|
x.back();
|
||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != 0) {
|
if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) {
|
||||||
throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||||
}
|
}
|
||||||
// End of JSON object
|
return;
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
throw jsonTokener.syntaxError("Expected a ',' or '}'");
|
throw x.syntaxError("Expected a ',' or '}'");
|
||||||
}
|
|
||||||
// Not at end of JSON object
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throws error if key violates strictMode
|
|
||||||
* @param jsonTokener Parses text as tokens
|
|
||||||
* @param jsonParserConfiguration Variable to pass parser custom configuration for json parsing.
|
|
||||||
* @param obj Value to be checked
|
|
||||||
*/
|
|
||||||
private static void checkKeyForStrictMode(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, Object obj) {
|
|
||||||
if (jsonParserConfiguration != null && jsonParserConfiguration.isStrictMode()) {
|
|
||||||
if(obj instanceof Boolean) {
|
|
||||||
throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be boolean", obj.toString()));
|
|
||||||
}
|
|
||||||
if(obj == JSONObject.NULL) {
|
|
||||||
throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be null", obj.toString()));
|
|
||||||
}
|
|
||||||
if(obj instanceof Number) {
|
|
||||||
throw jsonTokener.syntaxError(String.format("Strict mode error: key '%s' cannot be number", obj.toString()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,17 +401,12 @@ public class JSONObject {
|
|||||||
*/
|
*/
|
||||||
public JSONObject(Object bean) {
|
public JSONObject(Object bean) {
|
||||||
this();
|
this();
|
||||||
this.populateMap(bean, new JSONParserConfiguration());
|
this.populateMap(bean);
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject(Object bean, JSONParserConfiguration jsonParserConfiguration) {
|
|
||||||
this();
|
|
||||||
this.populateMap(bean, jsonParserConfiguration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONObject(Object bean, Set<Object> objectsRecord) {
|
private JSONObject(Object bean, Set<Object> objectsRecord) {
|
||||||
this();
|
this();
|
||||||
this.populateMap(bean, objectsRecord, new JSONParserConfiguration());
|
this.populateMap(bean, objectsRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -723,11 +674,13 @@ public class JSONObject {
|
|||||||
*/
|
*/
|
||||||
public boolean getBoolean(String key) throws JSONException {
|
public boolean getBoolean(String key) throws JSONException {
|
||||||
Object object = this.get(key);
|
Object object = this.get(key);
|
||||||
if (Boolean.FALSE.equals(object)
|
if (object.equals(Boolean.FALSE)
|
||||||
|| (object instanceof String && "false".equalsIgnoreCase((String) object))) {
|
|| (object instanceof String && ((String) object)
|
||||||
|
.equalsIgnoreCase("false"))) {
|
||||||
return false;
|
return false;
|
||||||
} else if (Boolean.TRUE.equals(object)
|
} else if (object.equals(Boolean.TRUE)
|
||||||
|| (object instanceof String && "true".equalsIgnoreCase((String) object))) {
|
|| (object instanceof String && ((String) object)
|
||||||
|
.equalsIgnoreCase("true"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw wrongValueFormatException(key, "Boolean", object, null);
|
throw wrongValueFormatException(key, "Boolean", object, null);
|
||||||
@ -1811,79 +1764,62 @@ public class JSONObject {
|
|||||||
* @throws JSONException
|
* @throws JSONException
|
||||||
* If a getter returned a non-finite number.
|
* If a getter returned a non-finite number.
|
||||||
*/
|
*/
|
||||||
private void populateMap(Object bean, JSONParserConfiguration jsonParserConfiguration) {
|
private void populateMap(Object bean) {
|
||||||
populateMap(bean, Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()), jsonParserConfiguration);
|
populateMap(bean, Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void populateMap(Object bean, Set<Object> objectsRecord) {
|
||||||
* Convert a bean into a json object
|
|
||||||
* @param bean object tobe converted
|
|
||||||
* @param objectsRecord set of all objects for this method
|
|
||||||
* @param jsonParserConfiguration json parser settings
|
|
||||||
*/
|
|
||||||
private void populateMap(Object bean, Set<Object> objectsRecord, JSONParserConfiguration jsonParserConfiguration) {
|
|
||||||
Class<?> klass = bean.getClass();
|
Class<?> klass = bean.getClass();
|
||||||
|
|
||||||
// If klass is a System class then set includeSuperClass to false.
|
// If klass is a System class then set includeSuperClass to false.
|
||||||
|
|
||||||
Method[] methods = getMethods(klass);
|
|
||||||
for (final Method method : methods) {
|
|
||||||
if (isValidMethod(method)) {
|
|
||||||
final String key = getKeyNameFromMethod(method);
|
|
||||||
if (key != null && !key.isEmpty()) {
|
|
||||||
processMethod(bean, objectsRecord, jsonParserConfiguration, method, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes method into json object entry if appropriate
|
|
||||||
* @param bean object being processed (owns the method)
|
|
||||||
* @param objectsRecord set of all objects for this method
|
|
||||||
* @param jsonParserConfiguration json parser settings
|
|
||||||
* @param method method being processed
|
|
||||||
* @param key name of the method
|
|
||||||
*/
|
|
||||||
private void processMethod(Object bean, Set<Object> objectsRecord, JSONParserConfiguration jsonParserConfiguration,
|
|
||||||
Method method, String key) {
|
|
||||||
try {
|
|
||||||
final Object result = method.invoke(bean);
|
|
||||||
if (result != null || jsonParserConfiguration.isUseNativeNulls()) {
|
|
||||||
// check cyclic dependency and throw error if needed
|
|
||||||
// the wrap and populateMap combination method is
|
|
||||||
// itself DFS recursive
|
|
||||||
if (objectsRecord.contains(result)) {
|
|
||||||
throw recursivelyDefinedObjectException(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
objectsRecord.add(result);
|
|
||||||
|
|
||||||
testValidity(result);
|
|
||||||
this.map.put(key, wrap(result, objectsRecord));
|
|
||||||
|
|
||||||
objectsRecord.remove(result);
|
|
||||||
|
|
||||||
closeClosable(result);
|
|
||||||
}
|
|
||||||
} catch (IllegalAccessException ignore) {
|
|
||||||
// ignore exception
|
|
||||||
} catch (IllegalArgumentException ignore) {
|
|
||||||
// ignore exception
|
|
||||||
} catch (InvocationTargetException ignore) {
|
|
||||||
// ignore exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a convenience method to simplify populate maps
|
|
||||||
* @param klass the name of the object being checked
|
|
||||||
* @return methods of klass
|
|
||||||
*/
|
|
||||||
private static Method[] getMethods(Class<?> klass) {
|
|
||||||
boolean includeSuperClass = klass.getClassLoader() != null;
|
boolean includeSuperClass = klass.getClassLoader() != null;
|
||||||
|
|
||||||
return includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
|
Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
|
||||||
|
for (final Method method : methods) {
|
||||||
|
final int modifiers = method.getModifiers();
|
||||||
|
if (Modifier.isPublic(modifiers)
|
||||||
|
&& !Modifier.isStatic(modifiers)
|
||||||
|
&& method.getParameterTypes().length == 0
|
||||||
|
&& !method.isBridge()
|
||||||
|
&& method.getReturnType() != Void.TYPE
|
||||||
|
&& isValidMethodName(method.getName())) {
|
||||||
|
final String key = getKeyNameFromMethod(method);
|
||||||
|
if (key != null && !key.isEmpty()) {
|
||||||
|
try {
|
||||||
|
final Object result = method.invoke(bean);
|
||||||
|
if (result != null) {
|
||||||
|
// check cyclic dependency and throw error if needed
|
||||||
|
// the wrap and populateMap combination method is
|
||||||
|
// itself DFS recursive
|
||||||
|
if (objectsRecord.contains(result)) {
|
||||||
|
throw recursivelyDefinedObjectException(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectsRecord.add(result);
|
||||||
|
|
||||||
|
testValidity(result);
|
||||||
|
this.map.put(key, wrap(result, objectsRecord));
|
||||||
|
|
||||||
|
objectsRecord.remove(result);
|
||||||
|
|
||||||
|
// we don't use the result anywhere outside of wrap
|
||||||
|
// if it's a resource we should be sure to close it
|
||||||
|
// after calling toString
|
||||||
|
if (result instanceof Closeable) {
|
||||||
|
try {
|
||||||
|
((Closeable) result).close();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException ignore) {
|
||||||
|
} catch (IllegalArgumentException ignore) {
|
||||||
|
} catch (InvocationTargetException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidMethodName(String name) {
|
private static boolean isValidMethodName(String name) {
|
||||||
@ -1901,7 +1837,7 @@ public class JSONObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class);
|
JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class);
|
||||||
if (annotationValueNotEmpty(annotation)) {
|
if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
|
||||||
return annotation.value();
|
return annotation.value();
|
||||||
}
|
}
|
||||||
String key;
|
String key;
|
||||||
@ -1927,46 +1863,6 @@ public class JSONObject {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* checks if the annotation is not null and the {@link JSONPropertyName#value()} is not null and is not empty.
|
|
||||||
* @param annotation the annotation to check
|
|
||||||
* @return true if the annotation and the value is not null and not empty, false otherwise.
|
|
||||||
*/
|
|
||||||
private static boolean annotationValueNotEmpty(JSONPropertyName annotation) {
|
|
||||||
return annotation != null && annotation.value() != null && !annotation.value().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the method is valid for the {@link #populateMap(Object, Set, JSONParserConfiguration)} use case
|
|
||||||
* @param method the Method to check
|
|
||||||
* @return true, if valid, false otherwise.
|
|
||||||
*/
|
|
||||||
private static boolean isValidMethod(Method method) {
|
|
||||||
final int modifiers = method.getModifiers();
|
|
||||||
return Modifier.isPublic(modifiers)
|
|
||||||
&& !Modifier.isStatic(modifiers)
|
|
||||||
&& method.getParameterTypes().length == 0
|
|
||||||
&& !method.isBridge()
|
|
||||||
&& method.getReturnType() != Void.TYPE
|
|
||||||
&& isValidMethodName(method.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* calls {@link Closeable#close()} on the input, if it is an instance of Closable.
|
|
||||||
* @param input the input to close, if possible.
|
|
||||||
*/
|
|
||||||
private static void closeClosable(Object input) {
|
|
||||||
// we don't use the result anywhere outside of wrap
|
|
||||||
// if it's a resource we should be sure to close it
|
|
||||||
// after calling toString
|
|
||||||
if (input instanceof Closeable) {
|
|
||||||
try {
|
|
||||||
((Closeable) input).close();
|
|
||||||
} catch (IOException ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the class hierarchy to see if the method or it's super
|
* Searches the class hierarchy to see if the method or it's super
|
||||||
* implementations and interfaces has the annotation.
|
* implementations and interfaces has the annotation.
|
||||||
@ -2010,7 +1906,7 @@ public class JSONObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If the superclass is Object, no annotations will be found any more
|
//If the superclass is Object, no annotations will be found any more
|
||||||
if (Object.class.equals(c.getSuperclass()))
|
if (c.getSuperclass().equals(Object.class))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -2068,7 +1964,7 @@ public class JSONObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If the superclass is Object, no annotations will be found any more
|
//If the superclass is Object, no annotations will be found any more
|
||||||
if (Object.class.equals(c.getSuperclass()))
|
if (c.getSuperclass().equals(Object.class))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -2854,13 +2750,13 @@ public class JSONObject {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (object instanceof JSONObject || object instanceof JSONArray
|
if (object instanceof JSONObject || object instanceof JSONArray
|
||||||
|| object instanceof JSONString || object instanceof String
|
|| NULL.equals(object) || object instanceof JSONString
|
||||||
|| object instanceof Byte || object instanceof Character
|
|| object instanceof Byte || object instanceof Character
|
||||||
|| object instanceof Short || object instanceof Integer
|
|| object instanceof Short || object instanceof Integer
|
||||||
|| object instanceof Long || object instanceof Boolean
|
|| object instanceof Long || object instanceof Boolean
|
||||||
|| object instanceof Float || object instanceof Double
|
|| object instanceof Float || object instanceof Double
|
||||||
|| object instanceof BigInteger || object instanceof BigDecimal
|
|| object instanceof String || object instanceof BigInteger
|
||||||
|| object instanceof Enum) {
|
|| object instanceof BigDecimal || object instanceof Enum) {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3114,4 +3010,24 @@ public class JSONObject {
|
|||||||
"JavaBean object contains recursively defined member variable of key " + quote(key)
|
"JavaBean object contains recursively defined member variable of key " + quote(key)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a prospective number, remove the leading zeros
|
||||||
|
* @param value prospective number
|
||||||
|
* @return number without leading zeros
|
||||||
|
*/
|
||||||
|
private static String removeLeadingZerosOfNumber(String value){
|
||||||
|
if (value.equals("-")){return value;}
|
||||||
|
boolean negativeFirstChar = (value.charAt(0) == '-');
|
||||||
|
int counter = negativeFirstChar ? 1:0;
|
||||||
|
while (counter < value.length()){
|
||||||
|
if (value.charAt(counter) != '0'){
|
||||||
|
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
|
||||||
|
return value.substring(counter);
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
if (negativeFirstChar) {return "-0";}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ public class JSONPointer {
|
|||||||
if (pointer == null) {
|
if (pointer == null) {
|
||||||
throw new NullPointerException("pointer cannot be null");
|
throw new NullPointerException("pointer cannot be null");
|
||||||
}
|
}
|
||||||
if (pointer.isEmpty() || "#".equals(pointer)) {
|
if (pointer.isEmpty() || pointer.equals("#")) {
|
||||||
this.refTokens = Collections.emptyList();
|
this.refTokens = Collections.emptyList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ public class JSONPointer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder rval = new StringBuilder();
|
StringBuilder rval = new StringBuilder("");
|
||||||
for (String token: this.refTokens) {
|
for (String token: this.refTokens) {
|
||||||
rval.append('/').append(escape(token));
|
rval.append('/').append(escape(token));
|
||||||
}
|
}
|
||||||
|
@ -511,21 +511,11 @@ public class JSONTokener {
|
|||||||
throw this.syntaxError("Missing value");
|
throw this.syntaxError("Missing value");
|
||||||
}
|
}
|
||||||
Object obj = JSONObject.stringToValue(string);
|
Object obj = JSONObject.stringToValue(string);
|
||||||
// if obj is a boolean, look at string
|
// Strict mode only allows strings with explicit double quotes
|
||||||
if (jsonParserConfiguration != null &&
|
if (jsonParserConfiguration != null &&
|
||||||
jsonParserConfiguration.isStrictMode()) {
|
jsonParserConfiguration.isStrictMode() &&
|
||||||
if (obj instanceof Boolean && !"true".equals(string) && !"false".equals(string)) {
|
obj instanceof String) {
|
||||||
// Strict mode only allows lowercase true or false
|
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj));
|
||||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase boolean", obj));
|
|
||||||
}
|
|
||||||
else if (obj == JSONObject.NULL && !"null".equals(string)) {
|
|
||||||
// Strint mode only allows lowercase null
|
|
||||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase null", obj));
|
|
||||||
}
|
|
||||||
else if (obj instanceof String) {
|
|
||||||
// Strict mode only allows strings with explicit double quotes
|
|
||||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -428,9 +428,6 @@ public class XML {
|
|||||||
config.isKeepNumberAsString()
|
config.isKeepNumberAsString()
|
||||||
? ((String) token)
|
? ((String) token)
|
||||||
: obj);
|
: obj);
|
||||||
} else if (obj == JSONObject.NULL) {
|
|
||||||
jsonObject.accumulate(config.getcDataTagName(),
|
|
||||||
config.isKeepStrings() ? ((String) token) : obj);
|
|
||||||
} else {
|
} else {
|
||||||
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
|
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
|
||||||
}
|
}
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
package org.json.junit;
|
|
||||||
|
|
||||||
import org.json.HTTPTokener;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
/**
|
|
||||||
* Tests for JSON-Java HTTPTokener.java
|
|
||||||
*/
|
|
||||||
public class HTTPTokenerTest {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing a simple unquoted token.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseSimpleToken() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("Content-Type");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("Content-Type", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing multiple tokens separated by whitespace.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseMultipleTokens() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("Content-Type application/json");
|
|
||||||
String token1 = tokener.nextToken();
|
|
||||||
String token2 = tokener.nextToken();
|
|
||||||
assertEquals("Content-Type", token1);
|
|
||||||
assertEquals("application/json", token2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing a double-quoted token.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseDoubleQuotedToken() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("\"application/json\"");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("application/json", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing a single-quoted token.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseSingleQuotedToken() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("'application/json'");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("application/json", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing a quoted token that includes spaces and semicolons.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseQuotedTokenWithSpaces() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("\"text/html; charset=UTF-8\"");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("text/html; charset=UTF-8", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that unterminated quoted strings throw a JSONException.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void throwExceptionOnUnterminatedString() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("\"incomplete");
|
|
||||||
JSONException exception = assertThrows(JSONException.class, tokener::nextToken);
|
|
||||||
assertTrue(exception.getMessage().contains("Unterminated string"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test behavior with empty input string.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseEmptyInput() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test behavior with input consisting only of whitespace.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseWhitespaceOnly() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener(" \t \n ");
|
|
||||||
String token = tokener.nextToken();
|
|
||||||
assertEquals("", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test parsing tokens separated by multiple whitespace characters.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void parseTokensWithMultipleWhitespace() {
|
|
||||||
HTTPTokener tokener = new HTTPTokener("GET /index.html");
|
|
||||||
String method = tokener.nextToken();
|
|
||||||
String path = tokener.nextToken();
|
|
||||||
assertEquals("GET", method);
|
|
||||||
assertEquals("/index.html", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -3997,56 +3997,6 @@ public class JSONObjectTest {
|
|||||||
assertThrows(JSONException.class, () -> { new JSONObject(tokener); });
|
assertThrows(JSONException.class, () -> { new JSONObject(tokener); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_strictModeWithMisCasedBooleanOrNullValue(){
|
|
||||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode();
|
|
||||||
try{
|
|
||||||
new JSONObject("{\"a\":True}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
try{
|
|
||||||
new JSONObject("{\"a\":TRUE}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
try{
|
|
||||||
new JSONObject("{\"a\":nUlL}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_strictModeWithInappropriateKey(){
|
|
||||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode();
|
|
||||||
|
|
||||||
// Parsing the following objects should fail
|
|
||||||
try{
|
|
||||||
new JSONObject("{true : 3}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
try{
|
|
||||||
new JSONObject("{TRUE : 3}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
try{
|
|
||||||
new JSONObject("{1 : 3}", jsonParserConfiguration);
|
|
||||||
fail("Expected an exception");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// No action, expected outcome
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to build nested map of max maxDepth
|
* Method to build nested map of max maxDepth
|
||||||
*
|
*
|
||||||
@ -4061,37 +4011,5 @@ public class JSONObjectTest {
|
|||||||
nestedMap.put("t", buildNestedMap(maxDepth - 1));
|
nestedMap.put("t", buildNestedMap(maxDepth - 1));
|
||||||
return nestedMap;
|
return nestedMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the behavior of the {@link JSONObject} when parsing a bean with null fields
|
|
||||||
* using a custom {@link JSONParserConfiguration} that enables the use of native nulls.
|
|
||||||
*
|
|
||||||
* <p>This test ensures that uninitialized fields in the bean are serialized correctly
|
|
||||||
* into the resulting JSON object, and their keys are present in the JSON string output.</p>
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void jsonObjectParseNullFieldsWithParserConfiguration() {
|
|
||||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration();
|
|
||||||
RecursiveBean bean = new RecursiveBean(null);
|
|
||||||
JSONObject jsonObject = new JSONObject(bean, jsonParserConfiguration.withUseNativeNulls(true));
|
|
||||||
assertTrue("name key should be present", jsonObject.has("name"));
|
|
||||||
assertTrue("ref key should be present", jsonObject.has("ref"));
|
|
||||||
assertTrue("ref2 key should be present", jsonObject.has("ref2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the behavior of the {@link JSONObject} when parsing a bean with null fields
|
|
||||||
* without using a custom {@link JSONParserConfiguration}.
|
|
||||||
*
|
|
||||||
* <p>This test ensures that uninitialized fields in the bean are not serialized
|
|
||||||
* into the resulting JSON object, and the object remains empty.</p>
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void jsonObjectParseNullFieldsWithoutParserConfiguration() {
|
|
||||||
RecursiveBean bean = new RecursiveBean(null);
|
|
||||||
JSONObject jsonObject = new JSONObject(bean);
|
|
||||||
assertTrue("JSONObject should be empty", jsonObject.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -775,8 +775,8 @@ public class XMLConfigurationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testToJSONArray_jsonOutput_withKeepNumberAsString() {
|
public void testToJSONArray_jsonOutput_withKeepNumberAsString() {
|
||||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><id>null</id><item id=\"01\"/><title>True</title></root>";
|
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\",null],\"title\":true}}");
|
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":true}}");
|
||||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||||
new XMLParserConfiguration().withKeepNumberAsString(true));
|
new XMLParserConfiguration().withKeepNumberAsString(true));
|
||||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||||
@ -787,25 +787,13 @@ public class XMLConfigurationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testToJSONArray_jsonOutput_withKeepBooleanAsString() {
|
public void testToJSONArray_jsonOutput_withKeepBooleanAsString() {
|
||||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><id>null</id><item id=\"01\"/><title>True</title></root>";
|
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0,null],\"title\":\"True\"}}");
|
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":\"True\"}}");
|
||||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||||
new XMLParserConfiguration().withKeepBooleanAsString(true));
|
new XMLParserConfiguration().withKeepBooleanAsString(true));
|
||||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* null is "null" when keepStrings == true
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testToJSONArray_jsonOutput_null_withKeepString() {
|
|
||||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>null</title></root>";
|
|
||||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"null\"}}");
|
|
||||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
|
||||||
new XMLParserConfiguration().withKeepStrings(true));
|
|
||||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test keepStrings behavior when setting keepBooleanAsString, keepNumberAsString
|
* Test keepStrings behavior when setting keepBooleanAsString, keepNumberAsString
|
||||||
*/
|
*/
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
package org.json.junit;
|
|
||||||
|
|
||||||
import org.json.XMLTokener;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.StringReader;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for JSON-Java XMLTokener.java
|
|
||||||
*/
|
|
||||||
public class XMLTokenerTest {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that nextCDATA() correctly extracts content from within a CDATA section.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNextCDATA() {
|
|
||||||
String xml = "This is <![CDATA[ some <CDATA> content ]]> after";
|
|
||||||
XMLTokener tokener = new XMLTokener(new StringReader(xml));
|
|
||||||
tokener.skipPast("<![CDATA[");
|
|
||||||
String cdata = tokener.nextCDATA();
|
|
||||||
assertEquals(" some <CDATA> content ", cdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that nextContent() returns plain text content before a tag.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNextContentWithText() {
|
|
||||||
String xml = "Some content<nextTag>";
|
|
||||||
XMLTokener tokener = new XMLTokener(xml);
|
|
||||||
Object content = tokener.nextContent();
|
|
||||||
assertEquals("Some content", content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that nextContent() returns '<' character when starting with a tag.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNextContentWithTag() {
|
|
||||||
String xml = "<tag>";
|
|
||||||
XMLTokener tokener = new XMLTokener(xml);
|
|
||||||
Object content = tokener.nextContent();
|
|
||||||
assertEquals('<', content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that nextEntity() resolves a known entity like & correctly.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNextEntityKnown() {
|
|
||||||
XMLTokener tokener = new XMLTokener("amp;");
|
|
||||||
Object result = tokener.nextEntity('&');
|
|
||||||
assertEquals("&", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that nextEntity() preserves unknown entities by returning them unchanged.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testNextEntityUnknown() {
|
|
||||||
XMLTokener tokener = new XMLTokener("unknown;");
|
|
||||||
tokener.next(); // skip 'u'
|
|
||||||
Object result = tokener.nextEntity('&');
|
|
||||||
assertEquals("&nknown;", result); // malformed start to simulate unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests skipPast() to ensure the cursor moves past the specified string.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSkipPast() {
|
|
||||||
String xml = "Ignore this... endHere more text";
|
|
||||||
XMLTokener tokener = new XMLTokener(xml);
|
|
||||||
tokener.skipPast("endHere");
|
|
||||||
assertEquals(' ', tokener.next()); // should be the space after "endHere"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user