public <T> T readValue (Class<T> type, Class elementType, JsonValue jsonData) {
		if (jsonData == null) return null;

		if (jsonData.isObject()) {
			String className = typeName == null ? null : jsonData.getString(typeName, null);
			if (className != null) {
				jsonData.remove(typeName);
				type = getClass(className);
				if (type == null) {
					try {
						type = (Class<T>)Class.forName(className);
					} catch (ClassNotFoundException ex) {
						throw new JsonException(ex);
					}
				}
			}

			if (type == null) {
				if (defaultSerializer != null) return (T)defaultSerializer.read(this, jsonData, type);
				return (T)jsonData;
			}

			if (type == String.class || type == Integer.class || type == Boolean.class || type == Float.class || type == Long.class
				|| type == Double.class || type == Short.class || type == Byte.class || type == Character.class
				|| Enum.class.isAssignableFrom(type)) {
				return readValue("value", type, jsonData);
			}

			if (typeName != null && Collection.class.isAssignableFrom(type)) {
				// JSON object wrapper to specify type.
				jsonData = jsonData.get("items");
				if (jsonData == null)
					throw new JsonException("Unable to convert object to collection: " + jsonData + " (" + type.getName() + ")");
			} else {
				JsonSerializer serializer = classToSerializer.get(type);
				if (serializer != null) return (T)serializer.read(this, jsonData, type);

				Object object = newInstance(type);

				if (object instanceof JsonSerializable) {
					((JsonSerializable)object).read(this, jsonData);
					return (T)object;
				}

				// JSON object special cases.
				if (object instanceof ObjectMap) {
					ObjectMap result = (ObjectMap)object;
					for (JsonValue child = jsonData.child; child != null; child = child.next)
						result.put(child.name(), readValue(elementType, null, child));
					return (T)result;
				}
				if (object instanceof Map) {
					Map result = (Map)object;
					for (JsonValue child = jsonData.child; child != null; child = child.next)
						result.put(child.name(), readValue(elementType, null, child));
					return (T)result;
				}

				readFields(object, jsonData);
				return (T)object;
			}
		}

		if (type != null) {
			JsonSerializer serializer = classToSerializer.get(type);
			if (serializer != null) return (T)serializer.read(this, jsonData, type);

			if (JsonSerializable.class.isAssignableFrom(type)) {
				// A Serializable may be read as an array, string, etc, even though it will be written as an object.
				Object object = newInstance(type);
				((JsonSerializable)object).read(this, jsonData);
				return (T)object;
			}
		}

		if (jsonData.isArray()) {
			// JSON array special cases.
			if (type == null || type == Object.class) type = (Class<T>)ArrayList.class;
			if (Collection.class.isAssignableFrom(type)) {
				Collection result = type.isInterface() ? new ArrayList() : (Collection)newInstance(type);
				for (JsonValue child = jsonData.child; child != null; child = child.next)
					result.add(readValue(elementType, null, child));
				return (T)result;
			}
			if (type.isArray()) {
				Class componentType = type.getComponentType();
				if (elementType == null) elementType = componentType;
				Object result = Array.newInstance(componentType, jsonData.size);
				int i = 0;
				for (JsonValue child = jsonData.child; child != null; child = child.next)
					Array.set(result, i++, readValue(elementType, null, child));
				return (T)result;
			}
			throw new JsonException("Unable to convert value to required type: " + jsonData + " (" + type.getName() + ")");
		}

		if (jsonData.isNumber()) {
			try {
				if (type == null || type == float.class || type == Float.class) return (T)(Float)jsonData.asFloat();
				if (type == int.class || type == Integer.class) return (T)(Integer)jsonData.asInt();
				if (type == long.class || type == Long.class) return (T)(Long)jsonData.asLong();
				if (type == double.class || type == Double.class) return (T)(Double)jsonData.asDouble();
				if (type == String.class) return (T)jsonData.asString();
				if (type == short.class || type == Short.class) return (T)(Short)jsonData.asShort();
				if (type == byte.class || type == Byte.class) return (T)(Byte)jsonData.asByte();
			} catch (NumberFormatException ignored) {
			}
			jsonData = new JsonValue(jsonData.asString());
		}

		if (jsonData.isBoolean()) {
			try {
				if (type == null || type == boolean.class || type == Boolean.class) return (T)(Boolean)jsonData.asBoolean();
			} catch (NumberFormatException ignored) {
			}
			jsonData = new JsonValue(jsonData.asString());
		}

		if (jsonData.isString()) {
			String string = jsonData.asString();
			if (type == null || type == String.class) return (T)string;
			try {
				if (type == int.class || type == Integer.class) return (T)Integer.valueOf(string);
				if (type == float.class || type == Float.class) return (T)Float.valueOf(string);
				if (type == long.class || type == Long.class) return (T)Long.valueOf(string);
				if (type == double.class || type == Double.class) return (T)Double.valueOf(string);
				if (type == short.class || type == Short.class) return (T)Short.valueOf(string);
				if (type == byte.class || type == Byte.class) return (T)Byte.valueOf(string);
			} catch (NumberFormatException ignored) {
			}
			if (type == boolean.class || type == Boolean.class) return (T)Boolean.valueOf(string);
			if (type == char.class || type == Character.class) return (T)(Character)string.charAt(0);
			if (Enum.class.isAssignableFrom(type)) {
				Enum[] constants = (Enum[])type.getEnumConstants();
				for (int i = 0, n = constants.length; i < n; i++) {
					Enum e = constants[i];
					if (string.equals(convertToString(e))) return (T)e;
				}
			}
			if (type == CharSequence.class) return (T)string;
			throw new JsonException("Unable to convert value to required type: " + jsonData + " (" + type.getName() + ")");
		}

		return null;
	}
public < T > T readValue ( Class < T > type , Class elementType , JsonValue jsonData ) { if ( jsonData == null ) return null ; if ( jsonData . isObject ( ) ) { String className = typeName == null ? null : jsonData . getString ( typeName , null ) ; if ( className != null ) { jsonData . remove ( typeName ) ; type = getClass ( className ) ; if ( type == null ) { try { type = ( Class < T > ) Class . forName ( className ) ; } catch ( ClassNotFoundException ex ) { throw new JsonException ( ex ) ; } } } if ( type == null ) { if ( defaultSerializer != null ) return ( T ) defaultSerializer . read ( this , jsonData , type ) ; return ( T ) jsonData ; } if ( type == String . class || type == Integer . class || type == Boolean . class || type == Float . class || type == Long . class || type == Double . class || type == Short . class || type == Byte . class || type == Character . class || Enum . class . isAssignableFrom ( type ) ) { return readValue ( "value" , type , jsonData ) ; } if ( typeName != null && Collection . class . isAssignableFrom ( type ) ) { jsonData = jsonData . get ( "items" ) ; if ( jsonData == null ) throw new JsonException ( "Unable to convert object to collection: " + jsonData + " (" + type . getName ( ) + ")" ) ; } else { JsonSerializer serializer = classToSerializer . get ( type ) ; if ( serializer != null ) return ( T ) serializer . read ( this , jsonData , type ) ; Object object = newInstance ( type ) ; if ( object instanceof JsonSerializable ) { ( ( JsonSerializable ) object ) . read ( this , jsonData ) ; return ( T ) object ; } if ( object instanceof ObjectMap ) { ObjectMap result = ( ObjectMap ) object ; for ( JsonValue child = jsonData . child ; child != null ; child = child . next ) result . put ( child . name ( ) , readValue ( elementType , null , child ) ) ; return ( T ) result ; } if ( object instanceof Map ) { Map result = ( Map ) object ; for ( JsonValue child = jsonData . child ; child != null ; child = child . next ) result . put ( child . name ( ) , readValue ( elementType , null , child ) ) ; return ( T ) result ; } readFields ( object , jsonData ) ; return ( T ) object ; } } if ( type != null ) { JsonSerializer serializer = classToSerializer . get ( type ) ; if ( serializer != null ) return ( T ) serializer . read ( this , jsonData , type ) ; if ( JsonSerializable . class . isAssignableFrom ( type ) ) { Object object = newInstance ( type ) ; ( ( JsonSerializable ) object ) . read ( this , jsonData ) ; return ( T ) object ; } } if ( jsonData . isArray ( ) ) { if ( type == null || type == Object . class ) type = ( Class < T > ) ArrayList . class ; if ( Collection . class . isAssignableFrom ( type ) ) { Collection result = type . isInterface ( ) ? new ArrayList ( ) : ( Collection ) newInstance ( type ) ; for ( JsonValue child = jsonData . child ; child != null ; child = child . next ) result . add ( readValue ( elementType , null , child ) ) ; return ( T ) result ; } if ( type . isArray ( ) ) { Class componentType = type . getComponentType ( ) ; if ( elementType == null ) elementType = componentType ; Object result = Array . newInstance ( componentType , jsonData . size ) ; int i = 0 ; for ( JsonValue child = jsonData . child ; child != null ; child = child . next ) Array . set ( result , i ++ , readValue ( elementType , null , child ) ) ; return ( T ) result ; } throw new JsonException ( "Unable to convert value to required type: " + jsonData + " (" + type . getName ( ) + ")" ) ; } if ( jsonData . isNumber ( ) ) { try { if ( type == null || type == float . class || type == Float . class ) return ( T ) ( Float ) jsonData . asFloat ( ) ; if ( type == int . class || type == Integer . class ) return ( T ) ( Integer ) jsonData . asInt ( ) ; if ( type == long . class || type == Long . class ) return ( T ) ( Long ) jsonData . asLong ( ) ; if ( type == double . class || type == Double . class ) return ( T ) ( Double ) jsonData . asDouble ( ) ; if ( type == String . class ) return ( T ) jsonData . asString ( ) ; if ( type == short . class || type == Short . class ) return ( T ) ( Short ) jsonData . asShort ( ) ; if ( type == byte . class || type == Byte . class ) return ( T ) ( Byte ) jsonData . asByte ( ) ; } catch ( NumberFormatException ignored ) { } jsonData = new JsonValue ( jsonData . asString ( ) ) ; } if ( jsonData . isBoolean ( ) ) { try { if ( type == null || type == boolean . class || type == Boolean . class ) return ( T ) ( Boolean ) jsonData . asBoolean ( ) ; } catch ( NumberFormatException ignored ) { } jsonData = new JsonValue ( jsonData . asString ( ) ) ; } if ( jsonData . isString ( ) ) { String string = jsonData . asString ( ) ; if ( type == null || type == String . class ) return ( T ) string ; try { if ( type == int . class || type == Integer . class ) return ( T ) Integer . valueOf ( string ) ; if ( type == float . class || type == Float . class ) return ( T ) Float . valueOf ( string ) ; if ( type == long . class || type == Long . class ) return ( T ) Long . valueOf ( string ) ; if ( type == double . class || type == Double . class ) return ( T ) Double . valueOf ( string ) ; if ( type == short . class || type == Short . class ) return ( T ) Short . valueOf ( string ) ; if ( type == byte . class || type == Byte . class ) return ( T ) Byte . valueOf ( string ) ; } catch ( NumberFormatException ignored ) { } if ( type == boolean . class || type == Boolean . class ) return ( T ) Boolean . valueOf ( string ) ; if ( type == char . class || type == Character . class ) return ( T ) ( Character ) string . charAt ( 0 ) ; if ( Enum . class . isAssignableFrom ( type ) ) { Enum [ ] constants = ( Enum [ ] ) type . getEnumConstants ( ) ; for ( int i = 0 , n = constants . length ; i < n ; i ++ ) { Enum e = constants [ i ] ; if ( string . equals ( convertToString ( e ) ) ) return ( T ) e ; } } if ( type == CharSequence . class ) return ( T ) string ; throw new JsonException ( "Unable to convert value to required type: " + jsonData + " (" + type . getName ( ) + ")" ) ; } return null ; }
@param type May be null if the type is unknown.
@param elementType May be null if the type is unknown.
@return May be null.