From 94bcbb26e6ef3a3fe2f5ec5ad94c8c2cc423e72c Mon Sep 17 00:00:00 2001 From: Gust Date: Sat, 4 Oct 2025 22:30:54 +0800 Subject: [PATCH] update jdwp ; fix utf8 issue; optimize json --- minijvm/c/jvm/garbage.c | 3 + minijvm/c/jvm/jdwp.c | 303 ++++++- .../com/sun/cldc/i18n/j2me/UTF_8_Writer.java | 8 +- .../main/java/org/mini/json/JsonParser.java | 834 ++++++++---------- 4 files changed, 642 insertions(+), 506 deletions(-) diff --git a/minijvm/c/jvm/garbage.c b/minijvm/c/jvm/garbage.c index d2dd9d0b..a968e13f 100644 --- a/minijvm/c/jvm/garbage.c +++ b/minijvm/c/jvm/garbage.c @@ -153,6 +153,9 @@ void _garbage_clear(GcCollector *collector) { void gc_pause(GcCollector *collector) { vm_share_lock(collector->jvm); collector->_garbage_thread_status = GARBAGE_THREAD_PAUSE; + while (collector->isgc) { + vm_share_timedwait(collector->jvm, 100); + } vm_share_unlock(collector->jvm); } diff --git a/minijvm/c/jvm/jdwp.c b/minijvm/c/jvm/jdwp.c index 9467734c..f0c9f5d4 100644 --- a/minijvm/c/jvm/jdwp.c +++ b/minijvm/c/jvm/jdwp.c @@ -1,7 +1,7 @@ // // Created by gust on 2017/9/20. // - +#include #include "jdwp.h" #include "jvm_util.h" #include "garbage.h" @@ -1622,44 +1622,67 @@ void invoke_method(s32 call_mode, JdwpPacket *req, JdwpPacket *res, JdwpClient * s32 ret = execute_method_impl(methodInfo, runtime); jdwpserver->thread_sync_ignore = 0; + jdwppacket_set_err(res, JDWP_ERROR_NONE); + + ValueType returnValue, exceptionValue; + memset(&returnValue, 0, sizeof(ValueType)); + memset(&exceptionValue, 0, sizeof(ValueType)); + if (ret == RUNTIME_STATUS_EXCEPTION) { + // Method threw an exception print_exception(runtime); - } - jdwppacket_set_err(res, JDWP_ERROR_NONE); - ValueType vt; - memset(&vt, 0, sizeof(ValueType)); - if (stack_size(runtime->stack) > stacksize) { - Utf8String *us = utf8_create_copy(methodInfo->descriptor); - utf8_substring(us, utf8_indexof_c(us, ")") + 1, us->length); - vt.type = getJdwpTag(us); - switch (getSimpleTag(vt.type)) { - case '8': - vt.value = pop_long(runtime->stack); - break; - case 'R': { - __refer r = pop_ref(runtime->stack); - vt.type = getInstanceOfClassTag(r);//recorrect type, may be Arraylist - vt.value = (s64) (intptr_t) r; - jdwp_client_hold_obj(client, r); + // Get the exception object from stack top + Instance *exception = (Instance *) pop_ref(runtime->stack); -// if (vt.type == 's') { -// s32 debug = 1; -// Utf8String *ustr = utf8_create(); -// jstring_2_utf8((Instance *) r, ustr); -// utf8_destroy(ustr); -// } - break; + // Set return value to default (void/null) + returnValue.type = 'V'; // void type + returnValue.value = 0; + + // Set exception object + if (exception) { + exceptionValue.type = getInstanceOfClassTag(exception); + exceptionValue.value = (s64) (intptr_t) exception; + jdwp_client_hold_obj(client, exception); + } else { + exceptionValue.type = 'L'; + exceptionValue.value = 0; + } + } else { + // Method completed normally + if (stack_size(runtime->stack) > stacksize) { + Utf8String *us = utf8_create_copy(methodInfo->descriptor); + utf8_substring(us, utf8_indexof_c(us, ")") + 1, us->length); + returnValue.type = getJdwpTag(us); + switch (getSimpleTag(returnValue.type)) { + case '8': + returnValue.value = pop_long(runtime->stack); + break; + case 'R': { + __refer r = pop_ref(runtime->stack); + returnValue.type = getInstanceOfClassTag(r);//recorrect type, may be Arraylist + returnValue.value = (s64) (intptr_t) r; + jdwp_client_hold_obj(client, r); + break; + } + default: + returnValue.value = pop_int(runtime->stack); } - default: - vt.value = pop_int(runtime->stack); + utf8_destroy(us); + } else { + // Void method + returnValue.type = 'V'; + returnValue.value = 0; } - utf8_destroy(us); + + // No exception + exceptionValue.type = 'L'; + exceptionValue.value = 0; } - writeValueType(res, &vt); - vt.type = 'L'; - vt.value = 0; - writeValueType(res, &vt); + + // Write return value and exception according to JDWP protocol + writeValueType(res, &returnValue); + writeValueType(res, &exceptionValue); jdwp_packet_put(jdwpserver, res); gc_move_objs_thread_2_gc(runtime); @@ -2241,28 +2264,224 @@ s32 jdwp_client_process(JdwpServer *jdwpserver, JdwpClient *client) { break; } case JDWP_CMD_ClassType_SetValues: {//3.2 - jvm_printf("[JDWP]%x not support\n", jdwppacket_get_cmd_err(req)); - jdwppacket_set_err(res, JDWP_ERROR_NOT_IMPLEMENTED); - jdwp_packet_put(jdwpserver, res); + JClass *ref = jdwppacket_read_refer(req); + if (is_class_exists(jdwpserver->jvm, ref)) { + gc_pause(jdwpserver->jvm->collector); + Runtime *runtime = jdwp_get_runtime(jdwpserver); + s32 fields = jdwppacket_read_int(req); + jdwppacket_set_err(res, JDWP_ERROR_NONE); + s32 i; + for (i = 0; i < fields; i++) { + FieldInfo *fi = jdwppacket_read_refer(req); + ValueType vt; + vt.type = getJdwpTag(fi->descriptor); + readValueType(req, &vt); + if (fi->access_flags & ACC_STATIC) { + c8 *ptr = getStaticFieldPtr(fi); + setPtrValue(vt.type, ptr, vt.value); + } + } + jdwp_packet_put(jdwpserver, res); + + gc_move_objs_thread_2_gc(runtime); + gc_resume(jdwpserver->jvm->collector); + } else { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_CLASS); + jdwp_packet_put(jdwpserver, res); + } break; } case JDWP_CMD_ClassType_InvokeMethod: {//3.3 invoke_method(CALL_MODE_STATIC, req, res, client); - //jvm_printf("[JDWP]%x not support\n", jdwppacket_get_cmd_err(req)); break; } case JDWP_CMD_ClassType_NewInstance: {//3.4 - jvm_printf("[JDWP]%x not support\n", jdwppacket_get_cmd_err(req)); - jdwppacket_set_err(res, JDWP_ERROR_NOT_IMPLEMENTED); - jdwp_packet_put(jdwpserver, res); + JClass *clazz = jdwppacket_read_refer(req); + if (is_class_exists(jdwpserver->jvm, clazz)) { + // Check if class is instantiable (not interface, not abstract, not array) + if ((clazz->cff.access_flags & ACC_INTERFACE) || + (clazz->cff.access_flags & ACC_ABSTRACT) || + clazz->mb.arr_type_index != 0) { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_CLASS); + jdwp_packet_put(jdwpserver, res); + break; + } + + Instance *thread = jdwppacket_read_refer(req); + MethodInfo *constructor = jdwppacket_read_refer(req); + s32 arguments = jdwppacket_read_int(req); + + // Validate constructor + if (!constructor || constructor->_this_class != clazz || + utf8_equals_c(constructor->name, "") != 1) { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_METHODID); + jdwp_packet_put(jdwpserver, res); + break; + } + + gc_pause(jdwpserver->jvm->collector); + Runtime *runtime = jdwp_get_runtime(jdwpserver); + + // Create new instance + Instance *newInstance = instance_create(runtime, clazz); + if (newInstance) { + jdwp_client_hold_obj(client, newInstance); + + // Create parameter stack for constructor + RuntimeStack *paraStack = NULL; + if (arguments > 0) { + paraStack = stack_create(arguments); + s32 i; + for (i = 0; i < arguments; i++) { + ValueType vt; + readValueType(req, &vt); + + switch (getSimpleTag(vt.type)) { + case '8': + push_long(paraStack, vt.value); + break; + case 'R': + push_ref(paraStack, (__refer) (intptr_t) vt.value); + break; + default: + push_int(paraStack, (s32) vt.value); + } + } + } + + // Execute constructor using instance_init_with_para + jdwpserver->thread_sync_ignore = 1; + + // Save current stack state + s32 saved_stack_size = stack_size(runtime->stack); + + // Build method signature and call constructor + Utf8String *methodSig = utf8_create_copy(constructor->descriptor); + instance_init_with_para(newInstance, runtime, utf8_cstr(methodSig), paraStack); + utf8_destroy(methodSig); + + jdwpserver->thread_sync_ignore = 0; + + // Check if constructor threw exception + s32 current_stack_size = stack_size(runtime->stack); + s32 ret = (current_stack_size > saved_stack_size) ? RUNTIME_STATUS_EXCEPTION + : RUNTIME_STATUS_NORMAL; + + jdwppacket_set_err(res, JDWP_ERROR_NONE); + + ValueType newInstanceValue, exceptionValue; + memset(&newInstanceValue, 0, sizeof(ValueType)); + memset(&exceptionValue, 0, sizeof(ValueType)); + + if (ret == RUNTIME_STATUS_EXCEPTION) { + // Constructor threw an exception + Instance *exception = (Instance *) pop_ref(runtime->stack); + + // Set return value to null + newInstanceValue.type = JDWP_TAG_OBJECT; + newInstanceValue.value = 0; + + // Set exception object + if (exception) { + exceptionValue.type = getInstanceOfClassTag(exception); + exceptionValue.value = (s64) (intptr_t) exception; + jdwp_client_hold_obj(client, exception); + } else { + exceptionValue.type = JDWP_TAG_OBJECT; + exceptionValue.value = 0; + } + } else { + // Constructor completed normally + newInstanceValue.type = getInstanceOfClassTag(newInstance); + newInstanceValue.value = (s64) (intptr_t) newInstance; + + // No exception + exceptionValue.type = JDWP_TAG_OBJECT; + exceptionValue.value = 0; + } + + // Write return value and exception + writeValueType(res, &newInstanceValue); + writeValueType(res, &exceptionValue); + + // Clean up parameter stack + if (paraStack) { + stack_destroy(paraStack); + } + + } else { + // Instance creation failed + jdwppacket_set_err(res, JDWP_ERROR_OUT_OF_MEMORY); + } + + jdwp_packet_put(jdwpserver, res); + gc_move_objs_thread_2_gc(runtime); + gc_resume(jdwpserver->jvm->collector); + } else { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_CLASS); + jdwp_packet_put(jdwpserver, res); + } break; } //set 4 case JDWP_CMD_ArrayType_NewInstance: {//4.1 - jvm_printf("[JDWP]%x not support\n", jdwppacket_get_cmd_err(req)); - jdwppacket_set_err(res, JDWP_ERROR_NOT_IMPLEMENTED); - jdwp_packet_put(jdwpserver, res); + JClass *arrayType = jdwppacket_read_refer(req); + if (is_class_exists(jdwpserver->jvm, arrayType)) { + // Check if it's actually an array type + if (arrayType->mb.arr_type_index == 0) { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_CLASS); + jdwp_packet_put(jdwpserver, res); + break; + } + + s32 length = jdwppacket_read_int(req); + + if (length < 0) { + // Negative array size + jdwppacket_set_err(res, JDWP_ERROR_ILLEGAL_ARGUMENT); + jdwp_packet_put(jdwpserver, res); + break; + } + + // Check for potential integer overflow in size calculation + s32 typeIdx = arrayType->mb.arr_type_index; + s32 width = DATA_TYPE_BYTES[typeIdx]; + if (length > 0 && width > 0) { + // Check if length * width would overflow (use 2147483647 as max s32) + if (length > (2147483647 - instance_base_size()) / width) { + jdwppacket_set_err(res, JDWP_ERROR_OUT_OF_MEMORY); + jdwp_packet_put(jdwpserver, res); + break; + } + } + + gc_pause(jdwpserver->jvm->collector); + Runtime *runtime = jdwp_get_runtime(jdwpserver); + + // Create array instance + Instance *newArray = jarray_create_by_class(runtime, length, arrayType); + if (newArray) { + jdwp_client_hold_obj(client, newArray); + jdwppacket_set_err(res, JDWP_ERROR_NONE); + + // Return new array instance + ValueType arrayValue; + arrayValue.type = getInstanceOfClassTag(newArray); + arrayValue.value = (s64) (intptr_t) newArray; + writeValueType(res, &arrayValue); + } else { + // Array creation failed + jdwppacket_set_err(res, JDWP_ERROR_OUT_OF_MEMORY); + } + + jdwp_packet_put(jdwpserver, res); + gc_move_objs_thread_2_gc(runtime); + gc_resume(jdwpserver->jvm->collector); + } else { + jdwppacket_set_err(res, JDWP_ERROR_INVALID_CLASS); + jdwp_packet_put(jdwpserver, res); + } break; } //set 5 diff --git a/minijvm/java/src/main/java/com/sun/cldc/i18n/j2me/UTF_8_Writer.java b/minijvm/java/src/main/java/com/sun/cldc/i18n/j2me/UTF_8_Writer.java index 60919d79..9b183c42 100644 --- a/minijvm/java/src/main/java/com/sun/cldc/i18n/j2me/UTF_8_Writer.java +++ b/minijvm/java/src/main/java/com/sun/cldc/i18n/j2me/UTF_8_Writer.java @@ -53,11 +53,11 @@ public void write(char cbuf[], int off, int len) throws IOException { if (Character.isHighSurrogate((char) unic)) { if (count >= len) { - throw new IllegalArgumentException("Incomplete surrogate pair"); + continue; } int c1 = cbuf[off + count]; if (!Character.isLowSurrogate((char) c1)) { - throw new IllegalArgumentException("Invalid surrogate pair"); + continue; } count++; int lead = unic & 0x3ff; @@ -129,11 +129,11 @@ public int sizeOf(char cbuf[], int off, int len) { if (Character.isHighSurrogate((char) unic)) { // Check array bounds before accessing next char if (count >= len) { - throw new IllegalArgumentException("Incomplete surrogate pair"); + continue; } int c1 = cbuf[off + count]; if (!Character.isLowSurrogate((char) c1)) { - throw new IllegalArgumentException("Invalid surrogate pair"); + continue; } count++; int lead = unic & 0x3ff; diff --git a/minijvm/java/src/main/java/org/mini/json/JsonParser.java b/minijvm/java/src/main/java/org/mini/json/JsonParser.java index 6e2dfc6c..f50b4cd6 100755 --- a/minijvm/java/src/main/java/org/mini/json/JsonParser.java +++ b/minijvm/java/src/main/java/org/mini/json/JsonParser.java @@ -1,51 +1,50 @@ package org.mini.json; -import org.mini.util.SysLog; - import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mini.util.SysLog; -/** - * same as jackson jason - * - * @param - */ public class JsonParser { + private List modules = new ArrayList<>(); - private List modules = new ArrayList(); private InjectableValues injectableValues = null; + ClassLoader classLoader; public JsonParser() { - SimpleModule module = new SimpleModule(); module.addDeserializer(List.class, new StdDeserializer(null) { @Override - public Object deserialize(JsonCell p, String types) { - return map2obj(p, ArrayList.class, types); + public Object deserialize(JsonParser.JsonCell p, String types) { + return JsonParser.this.map2obj(p, ArrayList.class, types); } }); module.addDeserializer(Set.class, new StdDeserializer(null) { @Override - public Object deserialize(JsonCell p, String types) { - return map2obj(p, LinkedHashSet.class, types); + public Object deserialize(JsonParser.JsonCell p, String types) { + return JsonParser.this.map2obj(p, LinkedHashSet.class, types); } }); module.addDeserializer(Map.class, new StdDeserializer(null) { - @Override - public Object deserialize(JsonCell p, String types) { - Map map = new HashMap(); - + public Object deserialize(JsonParser.JsonCell p, String types) { + Map map = new HashMap<>(); if (types == null || types.indexOf(',') < 0) { - JsonMap jsonMap = (JsonMap) p; - for (JsonCell key : jsonMap.keySet()) { + JsonParser.JsonMap jsonMap = (JsonParser.JsonMap) p; + for (JsonParser.JsonCell key : jsonMap.keySet()) { try { - Object K = map2obj(key, null, null); - Object V = map2obj(jsonMap.get(key), null, null); + Object K = JsonParser.this.map2obj(key, null, null); + Object V = JsonParser.this.map2obj(jsonMap.get(key), null, null); map.put(K, V); } catch (Exception e) { e.printStackTrace(); @@ -53,46 +52,40 @@ public Object deserialize(JsonCell p, String types) { } } else { String qualifier = types.substring(types.indexOf('<') + 1, types.lastIndexOf('>')); - //resolve key value qualifier int left = qualifier.indexOf('<'); int comma = qualifier.indexOf(','); int splitPos = comma; - if (left >= 0 && left < comma) { //the left type contains '<' + if (left >= 0 && left < comma) { int leftCnt = 1; int i; - //find matched right '>' for (i = left + 1; leftCnt > 0; i++) { - ;//start from '<', end with '>' char c = qualifier.charAt(i); - if (c == '<') leftCnt++; - if (c == '>') leftCnt--; + if (c == '<') + leftCnt++; + if (c == '>') + leftCnt--; } splitPos = i; } String keyClassName = qualifier.substring(0, splitPos).trim(); String valueClassName = qualifier.substring(splitPos + 1).trim(); - String keyType = keyClassName; - if (keyType.indexOf('<') >= 0) { + if (keyType.indexOf('<') >= 0) keyType = keyType.substring(0, keyType.indexOf('<')); - } String valueType = valueClassName; - if (valueType.indexOf('<') >= 0) { + if (valueType.indexOf('<') >= 0) valueType = valueType.substring(0, valueType.indexOf('<')); - } - keyType = TypeNameConverter.convertTypeNameToClassName(keyType); - valueType = TypeNameConverter.convertTypeNameToClassName(valueType); - JsonMap jsonMap = (JsonMap) p; - for (JsonCell key : jsonMap.keySet()) { + keyType = JsonParser.TypeNameConverter.convertTypeNameToClassName(keyType); + valueType = JsonParser.TypeNameConverter.convertTypeNameToClassName(valueType); + JsonParser.JsonMap jsonMap = (JsonParser.JsonMap) p; + for (JsonParser.JsonCell key : jsonMap.keySet()) { try { - Object K = map2obj(key, Class.forName(keyType, true, classLoader), keyClassName); - if (K instanceof Polymorphic) { - K = map2obj(key, ((Polymorphic) K).getType(), keyClassName); - } - Object V = map2obj(jsonMap.get(key), Class.forName(valueType, true, classLoader), valueClassName); - if (V instanceof Polymorphic) { - V = map2obj(jsonMap.get(key), ((Polymorphic) V).getType(), valueClassName); - } + Object K = JsonParser.this.map2obj(key, Class.forName(keyType, true, JsonParser.this.classLoader), keyClassName); + if (K instanceof JsonParser.Polymorphic) + K = JsonParser.this.map2obj(key, ((JsonParser.Polymorphic) K).getType(), keyClassName); + Object V = JsonParser.this.map2obj(jsonMap.get(key), Class.forName(valueType, true, JsonParser.this.classLoader), valueClassName); + if (V instanceof JsonParser.Polymorphic) + V = JsonParser.this.map2obj(jsonMap.get(key), ((JsonParser.Polymorphic) V).getType(), valueClassName); map.put(K, V); } catch (ClassNotFoundException e) { e.printStackTrace(); @@ -102,44 +95,42 @@ public Object deserialize(JsonCell p, String types) { return map; } }); - registerModule(module); } - public ClassLoader getClassLoader() { - return classLoader; + return this.classLoader; } public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } - /** - * 多态实现 - */ - public interface Polymorphic { + public static interface Polymorphic { Class getType(); } - public interface JsonCell { - int TYPE_MAP = 0; - int TYPE_LIST = 1; - int TYPE_STRING = 2; - int TYPE_NUMBER = 3; + public static interface JsonCell { + public static final int TYPE_MAP = 0; + + public static final int TYPE_LIST = 1; + + public static final int TYPE_STRING = 2; + + public static final int TYPE_NUMBER = 3; int getType(); } public static class JsonMap extends HashMap implements JsonCell { public int getType() { - return TYPE_MAP; + return 0; } } public static class JsonList extends ArrayList implements JsonCell { public int getType() { - return TYPE_LIST; + return 1; } } @@ -147,509 +138,461 @@ public static class JsonString implements JsonCell { String str; public JsonString(String s) { - str = s; + this.str = s; } public int getType() { - return TYPE_STRING; + return 2; } public String toString() { - return str; + return this.str; } } - public static class JsonNumber implements JsonCell { //include null too + public static class JsonNumber implements JsonCell { String numStr; public JsonNumber(String s) { - numStr = s; + this.numStr = s; } public int getType() { - return TYPE_NUMBER; + return 3; } public String toString() { - return numStr; + return this.numStr; } public float asFloat() { - return Float.parseFloat(numStr); + return Float.parseFloat(this.numStr); } public double asDouble() { - return Double.parseDouble(numStr); + return Double.parseDouble(this.numStr); } public int asInt() { - return Integer.parseInt(numStr); + return Integer.parseInt(this.numStr); } public long asLong() { - return Long.parseLong(numStr); + return Long.parseLong(this.numStr); } public byte asByte() { - return Byte.parseByte(numStr); + return Byte.parseByte(this.numStr); } public short asShort() { - return Short.parseShort(numStr); + return Short.parseShort(this.numStr); } public char asChar() { - return numStr.charAt(0); + return this.numStr.charAt(0); } public Object getValue(Class clazz) { - if (clazz == Integer.class || clazz == int.class) { - return Integer.decode(numStr); - } else if (clazz == Float.class || clazz == float.class) { - return Float.valueOf(numStr); - } else if (clazz == Long.class || clazz == long.class) { - return Long.decode(numStr); - } else if (clazz == Double.class || clazz == double.class) { - return Double.valueOf(numStr); - } else if (clazz == Short.class || clazz == short.class) { - return Short.decode(numStr); - } else if (clazz == Byte.class || clazz == byte.class) { - return Byte.decode(numStr); - } else if (clazz == Character.class || clazz == char.class) { - return Character.valueOf(numStr.charAt(0)); - } else if (clazz == Boolean.class || clazz == boolean.class) { - return Boolean.valueOf(numStr); - } else { - //guess - if (numStr.equalsIgnoreCase("true")) { - return Boolean.TRUE; - } - if (numStr.equalsIgnoreCase("false")) { - return Boolean.FALSE; - } - if (numStr.equals("null")) { - return null; - } - try { - return Integer.valueOf(numStr); - } catch (Exception e) { - } - try { - return Long.valueOf(numStr); - } catch (Exception e) { - } - try { - return Float.valueOf(numStr); - } catch (Exception e) { - } + if (clazz == Integer.class || clazz == int.class) + return Integer.decode(this.numStr); + if (clazz == Float.class || clazz == float.class) + return Float.valueOf(this.numStr); + if (clazz == Long.class || clazz == long.class) + return Long.decode(this.numStr); + if (clazz == Double.class || clazz == double.class) + return Double.valueOf(this.numStr); + if (clazz == Short.class || clazz == short.class) + return Short.decode(this.numStr); + if (clazz == Byte.class || clazz == byte.class) + return Byte.decode(this.numStr); + if (clazz == Character.class || clazz == char.class) + return Character.valueOf(this.numStr.charAt(0)); + if (clazz == Boolean.class || clazz == boolean.class) + return Boolean.valueOf(this.numStr); + if (this.numStr.equalsIgnoreCase("true")) + return Boolean.TRUE; + if (this.numStr.equalsIgnoreCase("false")) + return Boolean.FALSE; + if (this.numStr.equals("null")) + return null; + try { + return Integer.valueOf(this.numStr); + } catch (Exception exception) { try { - return Double.valueOf(numStr); - } catch (Exception e) { + return Long.valueOf(this.numStr); + } catch (Exception exception1) { + try { + return Float.valueOf(this.numStr); + } catch (Exception exception2) { + try { + return Double.valueOf(this.numStr); + } catch (Exception exception3) { + throw new IllegalArgumentException(); + } + } } - throw new IllegalArgumentException(); } } } - public abstract static class StdDeserializer { + public static abstract class StdDeserializer { public StdDeserializer(Class c) { - } - abstract public T deserialize(JsonCell p, String types); + public abstract T deserialize(JsonParser.JsonCell param1JsonCell, String param1String); } public static class SimpleModule { - Map serializeLib = new HashMap<>(); + Map serializeLib = (Map) new HashMap<>(); - public SimpleModule addDeserializer(Class key, StdDeserializer value) { - serializeLib.put(key, value); + public SimpleModule addDeserializer(Class key, JsonParser.StdDeserializer value) { + this.serializeLib.put(key, value); return this; } } - public void registerModule(SimpleModule module) { - modules.add(module); + this.modules.add(module); } private StdDeserializer findDeserializer(Class c) { - for (SimpleModule module : modules) { + for (SimpleModule module : this.modules) { StdDeserializer ds = module.serializeLib.get(c); - if (ds != null) { + if (ds != null) return ds; - } } return null; } - public static class InjectableValues { - Map values = new HashMap<>(); + Map values = (Map) new HashMap<>(); public void addValue(Class c, Object o) { - values.put(c, o); + this.values.put(c, o); } } public void setInjectableValues(InjectableValues values) { - injectableValues = values; + this.injectableValues = values; } - private Object findInjectableValues(Class c) { - if (injectableValues == null) return null; - Object ds = injectableValues.values.get(c); - if (ds != null) { + if (this.injectableValues == null) + return null; + Object ds = this.injectableValues.values.get(c); + if (ds != null) return ds; + return null; + } + + private static Method getMethodByName(String name, Class clazz) { + String mName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); + Method[] methods = clazz.getMethods(); + for (Method m : methods) { + if (m.getName().equals(mName) && (m.getParameterTypes()).length == 1) + return m; } return null; } + static class ParseToken { + String source; - static private int getNext(String s, int index, StringBuilder sb) { - sb.setLength(0); - int len = s.length(); - while (index < len) { - char ch = s.charAt(index); - if (ch == '\"') {//string - sb.append(ch); - index++; - while ((ch = s.charAt(index)) != '\"') {//string end - if (ch != '\\') {// - sb.append(ch); - } else { - index++; - ch = s.charAt(index); - if (ch == 'r') { - sb.append('\r'); - } else if (ch == 'n') { - sb.append('\n'); - } else if (ch == 't') { - sb.append('\t'); - } else if (ch == 'b') { - sb.append('\b'); - } else if (ch == 'f') { - sb.append('\f'); - } else if (ch == 'u') { - StringBuilder sb2 = new StringBuilder(); - for (int i = 0; i < 4; i++) { - index++; - sb2.append(s.charAt(index)); - } - sb.append((char) Integer.parseInt(sb2.toString(), 16)); - } else { - sb.append(ch); - } - } - index++; - } - sb.append(ch); - index++; - break; - } else if (ch == '{') { - boolean inQuot = false;//if brace in string - int braceCnt = 0;// - while (!((ch = s.charAt(index)) == '}' && braceCnt == 1 && !inQuot)) {// {"ab}cd"} - if (ch == '\"') {//string started - int slash = 0;// - for (int j = index - 1; j >= 0; j--) { - if (s.charAt(j) != '\\') {// process "abc\\\"def" - break; - } - slash++; - } - if (slash % 2 == 0) {// - inQuot = !inQuot; - } - } - // - if (!inQuot) { - if (ch == '{') { - braceCnt++; - } else if (ch == '}') { - braceCnt--; - } - } - sb.append(ch); - index++; - } - sb.append(ch); - index++; + int pos; + + Object parentContainer; + + JsonParser.JsonCell containerKey; + + JsonParser.JsonCell result; + + ParseToken(String source, int pos) { + this.source = source; + this.pos = pos; + } + + ParseToken(String source, int pos, Object parentContainer, JsonParser.JsonCell containerKey) { + this.source = source; + this.pos = pos; + this.parentContainer = parentContainer; + this.containerKey = containerKey; + } + + void skipWhitespace() { + while (this.pos < this.source.length() && Character.isWhitespace(this.source.charAt(this.pos))) + this.pos++; + } + + char currentChar() { + return (this.pos < this.source.length()) ? this.source.charAt(this.pos) : Character.MIN_VALUE; + } + + boolean isEnd() { + return (this.pos >= this.source.length()); + } + + void advance() { + this.pos++; + } + } + + private static void parseAndFillDirect(ParseToken token) { + token.skipWhitespace(); + if (token.isEnd()) + return; + char ch = token.currentChar(); + if (ch == '{') { + JsonMap newMap = new JsonMap<>(); + putIntoContainer(token.parentContainer, token.containerKey, newMap); + parseMapDirect(token, newMap); + } else if (ch == '[') { + JsonList newList = new JsonList<>(); + putIntoContainer(token.parentContainer, token.containerKey, newList); + parseListDirect(token, newList); + } else if (ch == '"') { + parseStringDirect(token); + putIntoContainer(token.parentContainer, token.containerKey, token.result); + } else { + parseNumberDirect(token); + putIntoContainer(token.parentContainer, token.containerKey, token.result); + } + } + + private static void putIntoContainer(Object container, JsonCell key, JsonCell value) { + if (container instanceof JsonMap) { + ((JsonMap) container).put(key, value); + } else if (container instanceof JsonList) { + ((JsonList) container).add(value); + } + } + + private static void parseStringDirect(ParseToken token) { + StringBuilder sb = new StringBuilder(); + token.advance(); + while (!token.isEnd()) { + char ch = token.currentChar(); + if (ch == '"') { + token.advance(); break; - } else if (ch == '[') { - boolean inQuot = false;// - int bracketCnt = 0;// - while (!((ch = s.charAt(index)) == ']' && bracketCnt == 1 && !inQuot)) {// - if (ch == '\"') {// - int slash = 0;// - for (int j = index - 1; j >= 0; j--) { - if (s.charAt(j) != '\\') { - break; - } - slash++; - } - if (slash % 2 == 0) {// - inQuot = !inQuot; - } - } - // - if (!inQuot) { - if (ch == '[') { - bracketCnt++; - } else if (ch == ']') { - bracketCnt--; + } + if (ch == '\\') { + token.advance(); + if (!token.isEnd()) { + ch = token.currentChar(); + if (ch == 'r') { + sb.append('\r'); + } else if (ch == 'n') { + sb.append('\n'); + } else if (ch == 't') { + sb.append('\t'); + } else if (ch == 'b') { + sb.append('\b'); + } else if (ch == 'f') { + sb.append('\f'); + } else if (ch == 'u') { + StringBuilder unicode = new StringBuilder(); + for (int i = 0; i < 4 && !token.isEnd(); i++) { + token.advance(); + if (!token.isEnd()) + unicode.append(token.currentChar()); } + sb.append((char) Integer.parseInt(unicode.toString(), 16)); + } else { + sb.append(ch); } - sb.append(ch); - index++; } - sb.append(ch); - index++; - break; - } else if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') { - index++; - } else if (ch == ':') { - sb.append(ch); - index++; - break; - } else if (ch == ',') { - sb.append(ch); - index++; - break; - } else if (ch == '}' || ch == ']') { - break; } else { - while (index < len) { - ch = s.charAt(index); - sb.append(ch); - if (index + 1 < len) { - char nextch = s.charAt(index + 1); - if (nextch == ',' || nextch == ':' || nextch == ']' || nextch == '}') { - break; - } - } - index++; - } - index++; - break; + sb.append(ch); } + token.advance(); } - //System.out.println("parse:" + sb.toString()); - return index; + token.result = new JsonString(sb.toString()); } - - static private JsonMap parseMap(String s, int pos) { - if (s == null || s.charAt(0) != '{') { - return null; - } else { - pos++; - StringBuilder sb = new StringBuilder(); - JsonMap map = new JsonMap(); - while (true) { - //name - pos = getNext(s, pos, sb); - if (sb.length() == 0) { - break; - } -// if (sb.charAt(0) != '"') { -// throw new RuntimeException("[JSON]error: field name need quotation : " + s); -// } - String name = sb.toString();//sb.substring(1, sb.length() - 1); - JsonCell cell = parse(name, 0); - //: - pos = getNext(s, pos, sb); - //value - pos = getNext(s, pos, sb); - String value = sb.toString(); - map.put(cell, parse(value, 0)); - //, - pos = getNext(s, pos, sb); - if (sb.length() == 0) { - break; - } - - } - return map; + private static void parseNumberDirect(ParseToken token) { + StringBuilder sb = new StringBuilder(); + while (!token.isEnd()) { + char ch = token.currentChar(); + if (ch == ',' || ch == '}' || ch == ']' || Character.isWhitespace(ch)) + break; + sb.append(ch); + token.advance(); } + token.result = new JsonNumber(sb.toString()); } - static private JsonList parseList(String s, int pos) { - if (s == null || s.charAt(0) != '[') { - return null; - } else { - pos++; - StringBuilder sb = new StringBuilder(); - JsonList list = new JsonList(); - while (true) { - //value - pos = getNext(s, pos, sb); - if (sb.length() == 0) { - break; - } - String value = sb.toString(); - list.add(parse(value, 0)); - //, - pos = getNext(s, pos, sb); - if (sb.length() == 0) { - break; - } + private static void parseMapDirect(ParseToken token, JsonMap targetMap) { + token.advance(); + while (!token.isEnd()) { + token.skipWhitespace(); + if (token.isEnd() || token.currentChar() == '}') { + if (!token.isEnd()) + token.advance(); + break; } - return list; + parseStringDirect(token); + JsonCell key = token.result; + token.skipWhitespace(); + if (!token.isEnd() && token.currentChar() == ':') + token.advance(); + token.skipWhitespace(); + Object tempParentContainer = token.parentContainer; + JsonCell tempContainerKey = token.containerKey; + token.parentContainer = targetMap; + token.containerKey = key; + parseAndFillDirect(token); + token.parentContainer = tempParentContainer; + token.containerKey = tempContainerKey; + token.skipWhitespace(); + if (!token.isEnd() && token.currentChar() == ',') + token.advance(); + token.skipWhitespace(); } - } - static private Method getMethodByName(String name, Class clazz) { - String mName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); - Method[] methods = clazz.getMethods(); - for (Method m : methods) { - if (m.getName().equals(mName) && m.getParameterTypes().length == 1) { - return m; + private static void parseListDirect(ParseToken token, JsonList targetList) { + token.advance(); + while (!token.isEnd()) { + token.skipWhitespace(); + if (token.isEnd() || token.currentChar() == ']') { + if (!token.isEnd()) + token.advance(); + break; } + Object tempParentContainer = token.parentContainer; + JsonCell tempContainerKey = token.containerKey; + token.parentContainer = targetList; + token.containerKey = null; + parseAndFillDirect(token); + token.parentContainer = tempParentContainer; + token.containerKey = tempContainerKey; + token.skipWhitespace(); + if (!token.isEnd() && token.currentChar() == ',') + token.advance(); + token.skipWhitespace(); } - return null; } - /** - * @param s - * @return - */ - static public final JsonCell parse(String s, int pos) { + public static final JsonCell parse(String s, int pos) { try { - if (s.length() == 0) { + if (s.length() == 0) return null; - } - s = s.trim(); - char ch = s.charAt(0); + ParseToken token = new ParseToken(s.trim(), 0); + char ch = token.currentChar(); if (ch == '{') { - return parseMap(s, pos); - } else if (ch == '[') { - return parseList(s, pos); - } else if (ch == '"') { - return new JsonString(s.substring(1, s.length() - 1)); - } else { - return new JsonNumber(s); + JsonMap rootMap = new JsonMap<>(); + parseMapDirect(token, rootMap); + return rootMap; + } + if (ch == '[') { + JsonList rootList = new JsonList<>(); + parseListDirect(token, rootList); + return rootList; + } + if (ch == '"') { + parseStringDirect(token); + return token.result; } + parseNumberDirect(token); + return token.result; } catch (Exception ex) { ex.printStackTrace(); + return null; } - return null; } - public Object map2obj(JsonCell json, Class clazz, String types) { - if (json == null) { + if (json == null) return null; - } try { - if (clazz == null && types == null && json.getType() == JsonCell.TYPE_MAP) { + JsonMap map; + JsonList list; + Object ins; + Class clazzQualified; + Field[] fields; + String typevar; + Collection collection; + if (clazz == null && types == null && json.getType() == 0) clazz = Map.class; - } StdDeserializer deser = findDeserializer(clazz); - if (deser != null) { // process list map set + if (deser != null) return deser.deserialize(json, types); - } - //other class switch (json.getType()) { - case JsonCell.TYPE_MAP: { - JsonMap map = (JsonMap) json; - Object ins = findInjectableValues(clazz);//get default value - if (ins == null) ins = clazz.newInstance(); - Field[] fields = clazz.getFields(); + case 0: + map = (JsonMap) json; + ins = findInjectableValues(clazz); + if (ins == null) + ins = clazz.newInstance(); + fields = clazz.getFields(); for (Field f : fields) { - Class c = f.getType(); + Class c = f.getType(); Object o = findInjectableValues(c); - if (o != null) { + if (o != null) f.set(ins, o); - } } for (JsonCell jc : map.keySet()) { - if (jc.getType() != JsonCell.TYPE_STRING) { + if (jc.getType() != 2) throw new RuntimeException("[JSON]error: field name need quotation : " + jc.toString()); - } String fieldName = ((JsonString) jc).toString(); JsonCell childJson = map.get(jc); -// if (fieldName.equals("COLOR_0")) { -// int debug = 1; -// } - Method method = getMethodByName(fieldName, clazz); if (method != null) { Type[] pt = method.getGenericParameterTypes(); - //System.out.println(method); - Class childClazz = method.getParameterTypes()[0]; + Class childClazz = method.getParameterTypes()[0]; try { - method.invoke(ins, map2obj(childJson, childClazz, pt[0].getTypeName())); + method.invoke(ins, new Object[]{map2obj(childJson, childClazz, pt[0].getTypeName())}); } catch (Exception e) { e.printStackTrace(); } - } else { - if (!(ins instanceof Polymorphic)) { - SysLog.warn("[JSON]" + clazz.getName() + " field '" + fieldName + "' setter not found."); - } + continue; } + if (!(ins instanceof Polymorphic)) + SysLog.warn("[JSON]" + clazz.getName() + " field '" + fieldName + "' setter not found.", new Object[0]); } return ins; - } - case JsonCell.TYPE_LIST: { - - if (types == null) { - SysLog.warn("[JSON] need type declare , class:" + clazz); - } - - if (clazz == null) { + case 1: + if (types == null) + SysLog.warn("[JSON] need type declare , class:" + clazz, new Object[0]); + if (clazz == null) clazz = ArrayList.class; - } - - JsonList list = (JsonList) json; + list = (JsonList) json; if (clazz.isArray()) { - String typevar = types; - if (typevar != null && typevar.indexOf('[') >= 0) { - typevar = typevar.substring(1); - } - + String str = types; + if (str != null && str.indexOf('[') >= 0) + str = str.substring(1); Object array = Array.newInstance(clazz.getComponentType(), list.size()); int i = 0; for (JsonCell cell : list) { - Object ins = map2obj(cell, clazz.getComponentType(), typevar); - Array.set(array, i, ins); + Object object = map2obj(cell, clazz.getComponentType(), str); + Array.set(array, i, object); i++; } return array; - } else { - Class clazzQualified = null; - String typevar = null; - if (types != null) { - typevar = types; - if (typevar.indexOf('<') > 0) { - typevar = typevar.substring(typevar.indexOf('<') + 1, typevar.length() - 1); - } - String className = typevar; - if (className.indexOf('<') >= 0) { - className = className.substring(0, className.indexOf('<')); - } - clazzQualified = Class.forName(className, true, classLoader); - } - Collection collection = (Collection) clazz.newInstance(); - for (JsonCell cell : list) { - Object ins = map2obj(cell, clazzQualified, typevar); - if (ins instanceof Polymorphic) { - ins = map2obj(cell, ((Polymorphic) ins).getType(), typevar); - } - collection.add(ins); - } - return collection; } - } - case JsonCell.TYPE_STRING: { + clazzQualified = null; + typevar = null; + if (types != null) { + typevar = types; + if (typevar.indexOf('<') > 0) + typevar = typevar.substring(typevar.indexOf('<') + 1, typevar.length() - 1); + String className = typevar; + if (className.indexOf('<') >= 0) + className = className.substring(0, className.indexOf('<')); + clazzQualified = Class.forName(className, true, this.classLoader); + } + collection = (Collection) clazz.newInstance(); + for (JsonCell cell : list) { + Object object = map2obj(cell, clazzQualified, typevar); + if (object instanceof Polymorphic) + object = map2obj(cell, ((Polymorphic) object).getType(), typevar); + collection.add(object); + } + return collection; + case 2: return ((JsonString) json).str; - } - case JsonCell.TYPE_NUMBER: { + case 3: return ((JsonNumber) json).getValue(clazz); - } - } } catch (Exception e) { System.err.println("error on parse " + clazz + " , str:" + json.toString()); @@ -658,78 +601,52 @@ public Object map2obj(JsonCell json, Class clazz, String types) { return null; } - public final T deserial(String s, Class clazz) { - return (T) deserial(s, clazz, null); + return deserial(s, clazz, null); } public final T deserial(String s, Class clazz, ClassLoader classLoader) { - return (T) deserial(s, clazz, classLoader, null); + return deserial(s, clazz, classLoader, null); } - public final T deserial(String s, Class clazz, ClassLoader classLoader, String types) { - if (clazz == null) throw new RuntimeException("Class can't null"); - if (classLoader == null) { + public final T deserial(String s, Class clazz, ClassLoader classLoader, String types) { + if (clazz == null) + throw new RuntimeException("Class can't null"); + if (classLoader == null) classLoader = Thread.currentThread().getContextClassLoader(); - } this.classLoader = classLoader; JsonCell json = parse(s, 0); return (T) map2obj(json, clazz, types); } - /** - * @param str - * @return true= - */ - static public final boolean isJsonString(String str) { - if (str == null) { + public static final boolean isJsonString(String str) { + if (str == null) return true; - } return (str.startsWith("{") || str.startsWith("[")); } - public static class TypeNameConverter { - - /** - * 将Java类型名称转换为其对应的类名表示形式。 - * "java.lang.String" -> "java.lang.String" - * "java.lang.String[]" -> "[Ljava.lang.String;" - * "int[][]" -> "[[I" - * - * @param typeName 类型名称,如 "java.lang.String" 或 "java.lang.String[]" 或 "int[][]" - * @return 转换后的类名,如 "java.lang.String" 对于数组类型,或者 "[Ljava.lang.String;" 对于非数组类型 - */ public static String convertTypeNameToClassName(String typeName) { if (typeName.endsWith("[]")) { - // 如果是数组类型,则转换为类名表示形式 int arrayDimension = 0; while (typeName.endsWith("[]")) { typeName = typeName.substring(0, typeName.length() - 2); arrayDimension++; } - if (isPrimitiveType(typeName)) { - // 如果是基本类型,使用JVM的内部表示 - return new String(new char[arrayDimension]).replace("\0", "[") + primitiveTypeToInternalForm(typeName); - } else { - // 如果是引用类型,使用标准的类名表示 - return new String(new char[arrayDimension]).replace("\0", "[") + "L" + typeName + ";"; - } - } else { - // 如果是非数组类型,直接返回或转换基本类型 - if (isPrimitiveType(typeName)) { - return primitiveTypeToInternalForm(typeName); - } else { - return typeName; - } + if (isPrimitiveType(typeName)) + return (new String(new char[arrayDimension])).replace("\000", "[") + primitiveTypeToInternalForm(typeName); + return (new String(new char[arrayDimension])).replace("\000", "[") + "L" + typeName + ";"; } + if (isPrimitiveType(typeName)) + return primitiveTypeToInternalForm(typeName); + return typeName; } private static boolean isPrimitiveType(String typeName) { - return typeName.equals("boolean") || typeName.equals("byte") || - typeName.equals("char") || typeName.equals("short") || - typeName.equals("int") || typeName.equals("long") || - typeName.equals("float") || typeName.equals("double"); + return (typeName.equals("boolean") || typeName.equals("byte") || typeName + .equals("char") || typeName.equals("short") || typeName + .equals("int") || typeName.equals("long") || typeName + .equals("float") || typeName.equals("double")); } private static String primitiveTypeToInternalForm(String typeName) { @@ -750,11 +667,8 @@ private static String primitiveTypeToInternalForm(String typeName) { return "F"; case "double": return "D"; - default: - throw new IllegalArgumentException("Invalid primitive type: " + typeName); } + throw new IllegalArgumentException("Invalid primitive type: " + typeName); } - } } -