jodd-json/src/main/java/jodd/json/JsonParser.java
protected Object parseObjectContent(Class targetType, Class valueKeyType, Class valueType) {
		// detect special case

		if (targetType == Object.class) {
			targetType = Map.class;
		}

		// continue

		targetType = replaceWithMappedTypeForPath(targetType);

		Object target;
		boolean isTargetTypeMap = true;
		boolean isTargetRealTypeMap = true;
		ClassDescriptor targetTypeClassDescriptor = null;
		TypeData typeData = null;

		if (targetType != null) {
			targetTypeClassDescriptor = ClassIntrospector.get().lookup(targetType);

			// find if the target is really a map
			// because when classMetadataName != null we are forcing
			// map usage locally in this method

			isTargetRealTypeMap = targetTypeClassDescriptor.isMap();

			typeData = jsonAnnotationManager.lookupTypeData(targetType);
		}

		if (isTargetRealTypeMap) {
			// resolve keys only for real maps
			path.push(KEYS);
			valueKeyType = replaceWithMappedTypeForPath(valueKeyType);
			path.pop();
		}

		if (classMetadataName == null) {
			// create instance of target type, no 'class' information
			target = newObjectInstance(targetType);

			isTargetTypeMap = isTargetRealTypeMap;
		} else {
			// all beans will be created first as a map
			target = mapSupplier.get();
		}

		boolean koma = false;

		mainloop:
		while (true) {
			skipWhiteSpaces();

			char c = input[ndx];

			if (c == '}') {
				if (koma) {
					syntaxError("Trailing comma");
				}

				ndx++;
				break;
			}

			koma = false;

			String key = parseString();
			String keyOriginal = key;

			skipWhiteSpaces();

			consume(':');

			skipWhiteSpaces();

			// read the type of the simple property

			PropertyDescriptor pd = null;
			Class propertyType = null;
			Class keyType = null;
			Class componentType = null;

			// resolve simple property

			if (!isTargetRealTypeMap) {
				// replace key with real property value
				key = jsonAnnotationManager.resolveRealName(targetType, key);
			}

			if (!isTargetTypeMap) {
				pd = targetTypeClassDescriptor.getPropertyDescriptor(key, true);

				if (pd != null) {
					propertyType = pd.getType();
					keyType = pd.resolveKeyType(true);
					componentType = pd.resolveComponentType(true);
				}
			}

			Object value;

			if (!isTargetTypeMap) {
				// *** inject into bean
					path.push(key);

					value = parseValue(propertyType, keyType, componentType);

					path.pop();

				if (typeData.rules.match(keyOriginal, !typeData.strict)) {

					if (pd != null) {
						if (lazy) {
							// need to resolve lazy value before injecting objects into it
							value = resolveLazyValue(value);
						}

						// only inject values if target property exist
						injectValueIntoObject(target, pd, value);
					}
				}
			}
			else {
				Object keyValue = key;

				if (valueKeyType != null) {
					keyValue = convertType(key, valueKeyType);
				}

				// *** add to map
				if (isTargetRealTypeMap) {
					path.push(VALUES, key);

					valueType = replaceWithMappedTypeForPath(valueType);
				} else {
					path.push(key);
				}


				value = parseValue(valueType, null, null);

				path.pop();

				((Map) target).put(keyValue, value);
			}

			skipWhiteSpaces();

			c = input[ndx];

			switch (c) {
				case '}': ndx++; break mainloop;
				case ',': ndx++; koma = true; break;
				default: syntaxError("Invalid char: expected } or ,");
			}
		}

		// done

		// convert Map to target type
		if (classMetadataName != null) {
			target = mapToBean.map2bean((Map) target, targetType);
		}

		return target;
	}
protected Object parseObjectContent(Class targetType, Class valueKeyType, Class valueType) {
		// detect special case

		if (targetType == Object.class) {
			targetType = Map.class;
		}

		// continue

		targetType = replaceWithMappedTypeForPath(targetType);

		Object target;
		boolean isTargetTypeMap = true;
		boolean isTargetRealTypeMap = true;
		ClassDescriptor targetTypeClassDescriptor = null;
		TypeData typeData = null;

		if (targetType != null) {
			targetTypeClassDescriptor = ClassIntrospector.get().lookup(targetType);

			// find if the target is really a map
			// because when classMetadataName != null we are forcing
			// map usage locally in this method

			isTargetRealTypeMap = targetTypeClassDescriptor.isMap();

			typeData = jsonAnnotationManager.lookupTypeData(targetType);
		}

		if (isTargetRealTypeMap) {
			// resolve keys only for real maps
			path.push(KEYS);
			valueKeyType = replaceWithMappedTypeForPath(valueKeyType);
			path.pop();
		}

		if (classMetadataName == null) {
			// create instance of target type, no 'class' information
			target = newObjectInstance(targetType);

			isTargetTypeMap = isTargetRealTypeMap;
		} else {
			// all beans will be created first as a map
			target = mapSupplier.get();
		}

		boolean koma = false;

		mainloop:
		while (true) {
			skipWhiteSpaces();

			char c = input[ndx];

			if (c == '}') {
				if (koma) {
					syntaxError("Trailing comma");
				}

				ndx++;
				break;
			}

			koma = false;

			String key = parseString();
			String keyOriginal = key;

			skipWhiteSpaces();

			consume(':');

			skipWhiteSpaces();

			// read the type of the simple property

			PropertyDescriptor pd = null;
			Class propertyType = null;
			Class keyType = null;
			Class componentType = null;

			// resolve simple property

			if (!isTargetRealTypeMap) {
				// replace key with real property value
				key = jsonAnnotationManager.resolveRealName(targetType, key);
			}

			if (!isTargetTypeMap) {
				pd = targetTypeClassDescriptor.getPropertyDescriptor(key, true);

				if (pd != null) {
					propertyType = pd.getType();
					keyType = pd.resolveKeyType(true);
					componentType = pd.resolveComponentType(true);
				}
			}

			Object value;

			if (!isTargetTypeMap) {
				// *** inject into bean
					path.push(key);

					value = parseValue(propertyType, keyType, componentType);

					path.pop();

				if (typeData.rules.match(keyOriginal, !typeData.strict)) {

					if (pd != null) {
						if (lazy) {
							// need to resolve lazy value before injecting objects into it
							value = resolveLazyValue(value);
						}

						// only inject values if target property exist
						injectValueIntoObject(target, pd, value);
					}
				}
			}
			else {
				Object keyValue = key;

				if (valueKeyType != null) {
					keyValue = convertType(key, valueKeyType);
				}

				// *** add to map
				if (isTargetRealTypeMap) {
					path.push(VALUES, key);

					valueType = replaceWithMappedTypeForPath(valueType);
				} else {
					path.push(key);
				}


				value = parseValue(valueType, null, null);

				path.pop();

				((Map) target).put(keyValue, value);
			}

			skipWhiteSpaces();

			c = input[ndx];

			switch (c) {
				case '}': ndx++; break mainloop;
				case ',': ndx++; koma = true; break;
				default: syntaxError("Invalid char: expected } or ,");
			}
		}

		// done

		// convert Map to target type
		if (classMetadataName != null) {
			target = mapToBean.map2bean((Map) target, targetType);
		}

		return target;
	}
Parses object, once when open bracket has been consumed.