线上代码对日志的记录,重要性自不必说。但是怎样记录日志也是有讲究的!
日志可以直接在每个方法中进行日志记录,优点是想怎么记就怎么记,缺点是记日志的代码可能会超过你的业务代码,可读性急剧下降,这也是日志框架蓬勃发展的源头。
日志也可以通过非业务代码侵入的形式进行记录,具体来说就是合作切面(aop)进行日志记录,好处自然是让业务更纯洁,缺点是运行性能会受到影响。
当然了,前面这些都不是本文的主题。本文的主题是,当你用切面进行日志记录时,然后fastjson是如何把你的业务代码给干掉的。
JsonObject.toJsonString(pj.getArgs()); 这是一个对入参的一个简单打印,至于使用fastjson的原因,自然是因为其输出字符的易读性。args是一个数组。那么这里会有什么问题?普通的参数自然是没有问题了。问题在于,fastjson转换对象为字符串时,报错了。为什么会这样?
注: 本文bug所现问题入参类型示例为:
public Object doSth(@RequestBody InBean in, HttpServletRequest request) { // do sth... }
切面报错为:
public Object deal(ProceedingJoinPoint pjp) throws Throwable { String argsStr = JSONObject.toJSONString(pjp.getArgs()); logger.info("入参:{}", argsStr); }
解析下fastjson源码过程:
初步进入源码:
// 直接调用json化方法 public static String toJSONString(Object object) { return toJSONString(object, emptyFilters); } // 转到复杂参数的调用 public static String toJSONString(Object object, SerializeFilter[] filters, SerializerFeature... features) { return toJSONString(object, SerializeConfig.globalInstance, filters, null, DEFAULT_GENERATE_FEATURE, features); } // 最终转换方法,1. 获取writer; 2. 处理filter; 3. 将数据定稿writer缓冲; 4. 返回缓冲数据给调用方 public static String toJSONString(Object object, // SerializeConfig config, // SerializeFilter[] filters, // String dateFormat, // int defaultFeatures, // SerializerFeature... features) { SerializeWriter out = new SerializeWriter(null, defaultFeatures, features); try { JSONSerializer serializer = new JSONSerializer(out, config); if (dateFormat != null && dateFormat.length() != 0) { serializer.setDateFormat(dateFormat); serializer.config(SerializerFeature.WriteDateUseDateFormat, true); } if (filters != null) { for (SerializeFilter filter : filters) { serializer.addFilter(filter); } } serializer.write(object); // 最核心方法 return out.toString(); } finally { out.close(); } }
深入内部调用,追根究底:
// 写方法的进一步操作 public final void write(Object object) { if (object == null) { out.writeNull(); return; } Class<?> clazz = object.getClass(); ObjectSerializer writer = getObjectWriter(clazz); // 关键,返回各种对应的序列化器, 如 ObjectArrayCodec try { writer.write(this, object, null, null, 0); // 调用对应的序列化器进行处理 } catch (IOException e) { throw new JSONException(e.getMessage(), e); } } // 追踪到在运行write方法时出的问题 ObjectArrayCodec public final void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { SerializeWriter out = serializer.out; Object[] array = (Object[]) object; if (object == null) { out.writeNull(SerializerFeature.WriteNullListAsEmpty); return; } int size = array.length; int end = size - 1; if (end == -1) { out.append("[]"); return; } SerialContext context = serializer.context; serializer.setContext(context, object, fieldName, 0); try { Class<?> preClazz = null; ObjectSerializer preWriter = null; out.append('['); if (out.isEnabled(SerializerFeature.PrettyFormat)) { serializer.incrementIndent(); serializer.println(); for (int i = 0; i < size; ++i) { if (i != 0) { out.write(','); serializer.println(); } serializer.write(array[i]); } serializer.decrementIdent(); serializer.println(); out.write(']'); return; } for (int i = 0; i < end; ++i) { Object item = array[i]; if (item == null) { out.append("null,"); } else { if (serializer.containsReference(item)) { serializer.writeReference(item); } else { Class<?> clazz = item.getClass(); if (clazz == preClazz) { preWriter.write(serializer, item, null, null, 0); } else { preClazz = clazz; preWriter = serializer.getObjectWriter(clazz); preWriter.write(serializer, item, null, null, 0); } } out.append(','); } } // 最后一个数组需要单独处理 Object item = array[end]; if (item == null) { out.append("null]"); } else { if (serializer.containsReference(item)) { serializer.writeReference(item); } else { serializer.writeWithFieldName(item, end); } out.append(']'); } } finally { serializer.context = context; } }
找到最后个出现问题的地方,发现再往下无法再跟踪:
// 最终报错是在这里 public final void writeWithFieldName(Object object, Object fieldName, Type fieldType, int fieldFeatures) { try { if (object == null) { out.writeNull(); return; } Class<?> clazz = object.getClass(); ObjectSerializer writer = getObjectWriter(clazz); // ASMSerializer_2_RequestFacade writer.write(this, object, fieldName, fieldType, fieldFeatures); // 此处使用asm语言写的代码,无法debug, 但是会抛出 IllegalStateException } catch (IOException e) { throw new JSONException(e.getMessage(), e); } }
检查最后一次出现的问题,搜索出现的标记,找到动态生成asm代码的文件:
// 动态生成代码 ASMSerializer_2_RequestFacade public JavaBeanSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) throws Exception { Class<?> clazz = beanInfo.beanType; if (clazz.isPrimitive()) { throw new JSONException("unsupportd class " + clazz.getName()); } JSONType jsonType = clazz.getAnnotation(JSONType.class); FieldInfo[] unsortedGetters = beanInfo.fields;; for (FieldInfo fieldInfo : unsortedGetters) { if (fieldInfo.field == null // && fieldInfo.method != null // && fieldInfo.method.getDeclaringClass().isInterface()) { return new JavaBeanSerializer(clazz); } } FieldInfo[] getters = beanInfo.sortedFields; boolean nativeSorted = beanInfo.sortedFields == beanInfo.fields; if (getters.length > 256) { return new JavaBeanSerializer(clazz); } for (FieldInfo getter : getters) { if (!ASMUtils.checkName(getter.getMember().getName())) { return new JavaBeanSerializer(clazz); } } String className = "ASMSerializer_" + seed.incrementAndGet() + "_" + clazz.getSimpleName(); String packageName = ASMSerializerFactory.class.getPackage().getName(); String classNameType = packageName.replace('.', '/') + "/" + className; String classNameFull = packageName + "." + className; ClassWriter cw = new ClassWriter(); cw.visit(V1_5 // , ACC_PUBLIC + ACC_SUPER // , classNameType // , JavaBeanSerializer // , new String[] { ObjectSerializer } // ); for (FieldInfo fieldInfo : getters) { if (fieldInfo.fieldClass.isPrimitive() // //|| fieldInfo.fieldClass.isEnum() // || fieldInfo.fieldClass == String.class) { continue; } new FieldWriter(cw, ACC_PUBLIC, fieldInfo.name + "_asm_fieldType", "Ljava/lang/reflect/Type;") // .visitEnd(); if (List.class.isAssignableFrom(fieldInfo.fieldClass)) { new FieldWriter(cw, ACC_PUBLIC, fieldInfo.name + "_asm_list_item_ser_", ObjectSerializer_desc) // .visitEnd(); } new FieldWriter(cw, ACC_PUBLIC, fieldInfo.name + "_asm_ser_", ObjectSerializer_desc) // .visitEnd(); } MethodVisitor mw = new MethodWriter(cw, ACC_PUBLIC, "<init>", "(" + desc(SerializeBeanInfo.class) + ")V", null, null); mw.visitVarInsn(ALOAD, 0); mw.visitVarInsn(ALOAD, 1); mw.visitMethodInsn(INVOKESPECIAL, JavaBeanSerializer, "<init>", "(" + desc(SerializeBeanInfo.class) + ")V"); // init _asm_fieldType for (int i = 0; i < getters.length; ++i) { FieldInfo fieldInfo = getters[i]; if (fieldInfo.fieldClass.isPrimitive() // // || fieldInfo.fieldClass.isEnum() // || fieldInfo.fieldClass == String.class) { continue; } mw.visitVarInsn(ALOAD, 0); if (fieldInfo.method != null) { mw.visitLdcInsn(com.alibaba.fastjson.asm.Type.getType(desc(fieldInfo.declaringClass))); mw.visitLdcInsn(fieldInfo.method.getName()); mw.visitMethodInsn(INVOKESTATIC, type(ASMUtils.class), "getMethodType", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Type;"); } else { mw.visitVarInsn(ALOAD, 0); mw.visitLdcInsn(i); mw.visitMethodInsn(INVOKESPECIAL, JavaBeanSerializer, "getFieldType", "(I)Ljava/lang/reflect/Type;"); } mw.visitFieldInsn(PUTFIELD, classNameType, fieldInfo.name + "_asm_fieldType", "Ljava/lang/reflect/Type;"); } mw.visitInsn(RETURN); mw.visitMaxs(4, 4); mw.visitEnd(); boolean DisableCircularReferenceDetect = false; if (jsonType != null) { for (SerializerFeature featrues : jsonType.serialzeFeatures()) { if (featrues == SerializerFeature.DisableCircularReferenceDetect) { DisableCircularReferenceDetect = true; break; } } } // 0 write // 1 writeNormal // 2 writeNonContext for (int i = 0; i < 3; ++i) { String methodName; boolean nonContext = DisableCircularReferenceDetect; boolean writeDirect = false; if (i == 0) { methodName = "write"; writeDirect = true; } else if (i == 1) { methodName = "writeNormal"; } else { writeDirect = true; nonContext = true; methodName = "writeDirectNonContext"; } Context context = new Context(getters, beanInfo, classNameType, writeDirect, nonContext); mw = new MethodWriter(cw, // ACC_PUBLIC, // methodName, // "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V", // null, // new String[] { "java/io/IOException" } // ); mw.visitVarInsn(ALOAD, Context.serializer); mw.visitFieldInsn(GETFIELD, JSONSerializer, "out", SerializeWriter_desc); mw.visitVarInsn(ASTORE, context.var("out")); if ((!nativeSorted) // && !context.writeDirect) { if (jsonType == null || jsonType.alphabetic()) { Label _else = new Label(); mw.visitVarInsn(ALOAD, context.var("out")); mw.visitMethodInsn(INVOKEVIRTUAL, SerializeWriter, "isSortField", "()Z"); mw.visitJumpInsn(IFNE, _else); mw.visitVarInsn(ALOAD, 0); mw.visitVarInsn(ALOAD, 1); mw.visitVarInsn(ALOAD, 2); mw.visitVarInsn(ALOAD, 3); mw.visitVarInsn(ALOAD, 4); mw.visitVarInsn(ILOAD, 5); mw.visitMethodInsn(INVOKEVIRTUAL, classNameType, "writeUnsorted", "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V"); mw.visitInsn(RETURN); mw.visitLabel(_else); } } // isWriteDoubleQuoteDirect if (context.writeDirect && !nonContext) { Label _direct = new Label(); Label _directElse = new Label(); mw.visitVarInsn(ALOAD, 0); mw.visitVarInsn(ALOAD, Context.serializer); mw.visitMethodInsn(INVOKEVIRTUAL, JavaBeanSerializer, "writeDirect", "(L" + JSONSerializer + ";)Z"); mw.visitJumpInsn(IFNE, _directElse); mw.visitVarInsn(ALOAD, 0); mw.visitVarInsn(ALOAD, 1); mw.visitVarInsn(ALOAD, 2); mw.visitVarInsn(ALOAD, 3); mw.visitVarInsn(ALOAD, 4); mw.visitVarInsn(ILOAD, 5); mw.visitMethodInsn(INVOKEVIRTUAL, classNameType, "writeNormal", "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V"); mw.visitInsn(RETURN); mw.visitLabel(_directElse); mw.visitVarInsn(ALOAD, context.var("out")); mw.visitLdcInsn(SerializerFeature.DisableCircularReferenceDetect.mask); mw.visitMethodInsn(INVOKEVIRTUAL, SerializeWriter, "isEnabled", "(I)Z"); mw.visitJumpInsn(IFEQ, _direct); mw.visitVarInsn(ALOAD, 0); mw.visitVarInsn(ALOAD, 1); mw.visitVarInsn(ALOAD, 2); mw.visitVarInsn(ALOAD, 3); mw.visitVarInsn(ALOAD, 4); mw.visitVarInsn(ILOAD, 5); mw.visitMethodInsn(INVOKEVIRTUAL, classNameType, "writeDirectNonContext", "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V"); mw.visitInsn(RETURN); mw.visitLabel(_direct); } mw.visitVarInsn(ALOAD, Context.obj); // obj mw.visitTypeInsn(CHECKCAST, type(clazz)); // serializer mw.visitVarInsn(ASTORE, context.var("entity")); // obj generateWriteMethod(clazz, mw, getters, context); mw.visitInsn(RETURN); mw.visitMaxs(7, context.variantIndex + 2); mw.visitEnd(); } if (!nativeSorted) { // sortField support Context context = new Context(getters, beanInfo, classNameType, false, DisableCircularReferenceDetect); mw = new MethodWriter(cw, ACC_PUBLIC, "writeUnsorted", "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V", null, new String[] { "java/io/IOException" }); mw.visitVarInsn(ALOAD, Context.serializer); mw.visitFieldInsn(GETFIELD, JSONSerializer, "out", SerializeWriter_desc); mw.visitVarInsn(ASTORE, context.var("out")); mw.visitVarInsn(ALOAD, Context.obj); // obj mw.visitTypeInsn(CHECKCAST, type(clazz)); // serializer mw.visitVarInsn(ASTORE, context.var("entity")); // obj generateWriteMethod(clazz, mw, unsortedGetters, context); mw.visitInsn(RETURN); mw.visitMaxs(7, context.variantIndex + 2); mw.visitEnd(); } // 0 writeAsArray // 1 writeAsArrayNormal // 2 writeAsArrayNonContext for (int i = 0; i < 3; ++i) { String methodName; boolean nonContext = DisableCircularReferenceDetect; boolean writeDirect = false; if (i == 0) { methodName = "writeAsArray"; writeDirect = true; } else if (i == 1) { methodName = "writeAsArrayNormal"; } else { writeDirect = true; nonContext = true; methodName = "writeAsArrayNonContext"; } Context context = new Context(getters, beanInfo, classNameType, writeDirect, nonContext); mw = new MethodWriter(cw, ACC_PUBLIC, methodName, "(L" + JSONSerializer + ";Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;I)V", null, new String[] { "java/io/IOException" }); mw.visitVarInsn(ALOAD, Context.serializer); mw.visitFieldInsn(GETFIELD, JSONSerializer, "out", SerializeWriter_desc); mw.visitVarInsn(ASTORE, context.var("out")); mw.visitVarInsn(ALOAD, Context.obj); // obj mw.visitTypeInsn(CHECKCAST, type(clazz)); // serializer mw.visitVarInsn(ASTORE, context.var("entity")); // obj generateWriteAsArray(clazz, mw, getters, context); mw.visitInsn(RETURN); mw.visitMaxs(7, context.variantIndex + 2); mw.visitEnd(); } byte[] code = cw.toByteArray(); Class<?> exampleClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length); Constructor<?> constructor = exampleClass.getConstructor(SerializeBeanInfo.class); Object instance = constructor.newInstance(beanInfo); return (JavaBeanSerializer) instance; } View Code
再回退到上一步,查找调用链路:
// 如果没有找到,就创建一个类 public ObjectSerializer getObjectWriter(Class<?> clazz) { return getObjectWriter(clazz, true); } // classLoader 多次加载 private ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) { ObjectSerializer writer = serializers.get(clazz); if (writer == null) { try { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) { if (!(o instanceof AutowiredObjectSerializer)) { continue; } AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o; for (Type forType : autowired.getAutowiredFor()) { put(forType, autowired); } } } catch (ClassCastException ex) { // skip } writer = serializers.get(clazz); } if (writer == null) { final ClassLoader classLoader = JSON.class.getClassLoader(); if (classLoader != Thread.currentThread().getContextClassLoader()) { try { for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) { if (!(o instanceof AutowiredObjectSerializer)) { continue; } AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o; for (Type forType : autowired.getAutowiredFor()) { put(forType, autowired); } } } catch (ClassCastException ex) { // skip } writer = serializers.get(clazz); } } if (writer == null) { if (Map.class.isAssignableFrom(clazz)) { put(clazz, MapSerializer.instance); } else if (List.class.isAssignableFrom(clazz)) { put(clazz, ListSerializer.instance); } else if (Collection.class.isAssignableFrom(clazz)) { put(clazz, CollectionCodec.instance); } else if (Date.class.isAssignableFrom(clazz)) { put(clazz, DateCodec.instance); } else if (JSONAware.class.isAssignableFrom(clazz)) { put(clazz, JSONAwareSerializer.instance); } else if (JSONSerializable.class.isAssignableFrom(clazz)) { put(clazz, JSONSerializableSerializer.instance); } else if (JSONStreamAware.class.isAssignableFrom(clazz)) { put(clazz, MiscCodec.instance); } else if (clazz.isEnum() || (clazz.getSuperclass() != null && clazz.getSuperclass().isEnum())) { JSONType jsonType = clazz.getAnnotation(JSONType.class); if (jsonType != null && jsonType.serializeEnumAsJavaBean()) { put(clazz, createJavaBeanSerializer(clazz)); } else { put(clazz, EnumSerializer.instance); } } else if (clazz.isArray()) { Class<?> componentType = clazz.getComponentType(); ObjectSerializer compObjectSerializer = getObjectWriter(componentType); put(clazz, new ArraySerializer(componentType, compObjectSerializer)); } else if (Throwable.class.isAssignableFrom(clazz)) { SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy); beanInfo.features |= SerializerFeature.WriteClassName.mask; put(clazz, new JavaBeanSerializer(beanInfo)); } else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) { put(clazz, MiscCodec.instance); } else if (Appendable.class.isAssignableFrom(clazz)) { put(clazz, AppendableSerializer.instance); } else if (Charset.class.isAssignableFrom(clazz)) { put(clazz, ToStringSerializer.instance); } else if (Enumeration.class.isAssignableFrom(clazz)) { put(clazz, EnumerationSerializer.instance); } else if (Calendar.class.isAssignableFrom(clazz) // || XMLGregorianCalendar.class.isAssignableFrom(clazz)) { put(clazz, CalendarCodec.instance); } else if (Clob.class.isAssignableFrom(clazz)) { put(clazz, ClobSeriliazer.instance); } else if (TypeUtils.isPath(clazz)) { put(clazz, ToStringSerializer.instance); } else if (Iterator.class.isAssignableFrom(clazz)) { put(clazz, MiscCodec.instance); } else { String className = clazz.getName(); if (className.startsWith("java.awt.") // && AwtCodec.support(clazz) // ) { // awt if (!awtError) { try { put(Class.forName("java.awt.Color"), AwtCodec.instance); put(Class.forName("java.awt.Font"), AwtCodec.instance); put(Class.forName("java.awt.Point"), AwtCodec.instance); put(Class.forName("java.awt.Rectangle"), AwtCodec.instance); } catch (Throwable e) { awtError = true; // skip } } return AwtCodec.instance; } // jdk8 if ((!jdk8Error) // && (className.startsWith("java.time.") // || className.startsWith("java.util.Optional") // )) { try { put(Class.forName("java.time.LocalDateTime"), Jdk8DateCodec.instance); put(Class.forName("java.time.LocalDate"), Jdk8DateCodec.instance); put(Class.forName("java.time.LocalTime"), Jdk8DateCodec.instance); put(Class.forName("java.time.ZonedDateTime"), Jdk8DateCodec.instance); put(Class.forName("java.time.OffsetDateTime"), Jdk8DateCodec.instance); put(Class.forName("java.time.OffsetTime"), Jdk8DateCodec.instance); put(Class.forName("java.time.ZoneOffset"), Jdk8DateCodec.instance); put(Class.forName("java.time.ZoneRegion"), Jdk8DateCodec.instance); put(Class.forName("java.time.Period"), Jdk8DateCodec.instance); put(Class.forName("java.time.Duration"), Jdk8DateCodec.instance); put(Class.forName("java.time.Instant"), Jdk8DateCodec.instance); put(Class.forName("java.util.Optional"), OptionalCodec.instance); put(Class.forName("java.util.OptionalDouble"), OptionalCodec.instance); put(Class.forName("java.util.OptionalInt"), OptionalCodec.instance); put(Class.forName("java.util.OptionalLong"), OptionalCodec.instance); writer = serializers.get(clazz); if (writer != null) { return writer; } } catch (Throwable e) { // skip jdk8Error = true; } } if ((!oracleJdbcError) // && className.startsWith("oracle.sql.")) { try { put(Class.forName("oracle.sql.DATE"), DateCodec.instance); put(Class.forName("oracle.sql.TIMESTAMP"), DateCodec.instance); writer = serializers.get(clazz); if (writer != null) { return writer; } } catch (Throwable e) { // skip oracleJdbcError = true; } } if ((!springfoxError) // && className.equals("springfox.documentation.spring.web.json.Json")) { try { put(Class.forName("springfox.documentation.spring.web.json.Json"), // SwaggerJsonSerializer.instance); writer = serializers.get(clazz); if (writer != null) { return writer; } } catch (ClassNotFoundException e) { // skip springfoxError = true; } } if ((!guavaError) // && className.startsWith("com.google.common.collect.")) { try { put(Class.forName("com.google.common.collect.HashMultimap"), // GuavaCodec.instance); put(Class.forName("com.google.common.collect.LinkedListMultimap"), // GuavaCodec.instance); put(Class.forName("com.google.common.collect.ArrayListMultimap"), // GuavaCodec.instance); put(Class.forName("com.google.common.collect.TreeMultimap"), // GuavaCodec.instance); writer = serializers.get(clazz); if (writer != null) { return writer; } } catch (ClassNotFoundException e) { // skip guavaError = true; } } if (className.equals("net.sf.json.JSONNull")) { try { put(Class.forName("net.sf.json.JSONNull"), // MiscCodec.instance); } catch (ClassNotFoundException e) { // skip } writer = serializers.get(clazz); if (writer != null) { return writer; } } if (TypeUtils.isProxy(clazz)) { Class<?> superClazz = clazz.getSuperclass(); ObjectSerializer superWriter = getObjectWriter(superClazz); put(clazz, superWriter); return superWriter; } // asm创建类是在这里生效的 if (create) { put(clazz, createJavaBeanSerializer(clazz)); } } writer = serializers.get(clazz); } return writer; }
往前追踪,发现入口:
// TypeUtils, 获取所有get方法。 public static List<FieldInfo> computeGetters(Class<?> clazz, // JSONType jsonType, // Map<String, String> aliasMap, // Map<String, Field> fieldCacheMap, // boolean sorted, // PropertyNamingStrategy propertyNamingStrategy // ) { Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<String, FieldInfo>(); for (Method method : clazz.getMethods()) { String methodName = method.getName(); int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0; String label = null; if (Modifier.isStatic(method.getModifiers())) { continue; } if (method.getReturnType().equals(Void.TYPE)) { continue; } if (method.getParameterTypes().length != 0) { continue; } if (method.getReturnType() == ClassLoader.class) { continue; } if (method.getName().equals("getMetaClass") && method.getReturnType().getName().equals("groovy.lang.MetaClass")) { continue; } JSONField annotation = method.getAnnotation(JSONField.class); if (annotation == null) { annotation = getSuperMethodAnnotation(clazz, method); } if (annotation != null) { if (!annotation.serialize()) { continue; } ordinal = annotation.ordinal(); serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures()); parserFeatures = Feature.of(annotation.parseFeatures()); if (annotation.name().length() != 0) { String propertyName = annotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } FieldInfo fieldInfo = new FieldInfo(propertyName, method, null, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, null, label); fieldInfoMap.put(propertyName, fieldInfo); continue; } if (annotation.label().length() != 0) { label = annotation.label(); } } if (methodName.startsWith("get")) { if (methodName.length() < 4) { continue; } if (methodName.equals("getClass")) { continue; } if (methodName.equals("getDeclaringClass") && clazz.isEnum()) { continue; } char c3 = methodName.charAt(3); String propertyName; if (Character.isUpperCase(c3) // || c3 > 512 // for unicode method name ) { if (compatibleWithJavaBean) { propertyName = decapitalize(methodName.substring(3)); } else { propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); } propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName,3); } else if (c3 == '_') { propertyName = methodName.substring(4); } else if (c3 == 'f') { propertyName = methodName.substring(3); } else if (methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))) { propertyName = decapitalize(methodName.substring(3)); } else { continue; } boolean ignore = isJSONTypeIgnore(clazz, propertyName); if (ignore) { continue; } //假如bean的field很多的情况一下,轮询时将大大降低效率 Field field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap); if (field == null && propertyName.length() > 1) { char ch = propertyName.charAt(1); if (ch >= 'A' && ch <= 'Z') { String javaBeanCompatiblePropertyName = decapitalize(methodName.substring(3)); field = ParserConfig.getFieldFromCache(javaBeanCompatiblePropertyName, fieldCacheMap); } } JSONField fieldAnnotation = null; if (field != null) { fieldAnnotation = field.getAnnotation(JSONField.class); if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } } if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } if (methodName.startsWith("is")) { if (methodName.length() < 3) { continue; } if (method.getReturnType() != Boolean.TYPE && method.getReturnType() != Boolean.class) { continue; } char c2 = methodName.charAt(2); String propertyName; if (Character.isUpperCase(c2)) { if (compatibleWithJavaBean) { propertyName = decapitalize(methodName.substring(2)); } else { propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3); } propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName,2); } else if (c2 == '_') { propertyName = methodName.substring(3); } else if (c2 == 'f') { propertyName = methodName.substring(2); } else { continue; } Field field = ParserConfig.getFieldFromCache(propertyName,fieldCacheMap); if (field == null) { field = ParserConfig.getFieldFromCache(methodName,fieldCacheMap); } JSONField fieldAnnotation = null; if (field != null) { fieldAnnotation = field.getAnnotation(JSONField.class); if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } } if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } //优先选择get if (fieldInfoMap.containsKey(propertyName)) { continue; } FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } } for (Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; } JSONField fieldAnnotation = field.getAnnotation(JSONField.class); int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0; String propertyName = field.getName(); String label = null; if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } if (!fieldInfoMap.containsKey(propertyName)) { FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, null, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } } List<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>(); boolean containsAll = false; String[] orders = null; JSONType annotation = clazz.getAnnotation(JSONType.class); if (annotation != null) { orders = annotation.orders(); if (orders != null && orders.length == fieldInfoMap.size()) { containsAll = true; for (String item : orders) { if (!fieldInfoMap.containsKey(item)) { containsAll = false; break; } } } else { containsAll = false; } } if (containsAll) { for (String item : orders) { FieldInfo fieldInfo = fieldInfoMap.get(item); fieldInfoList.add(fieldInfo); } } else { for (FieldInfo fieldInfo : fieldInfoMap.values()) { fieldInfoList.add(fieldInfo); } if (sorted) { Collections.sort(fieldInfoList); } } return fieldInfoList; } // SerializeConfig, 创建java bean. public ObjectSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) { JSONType jsonType = beanInfo.jsonType; if (jsonType != null) { Class<?> serializerClass = jsonType.serializer(); if (serializerClass != Void.class) { try { Object seralizer = serializerClass.newInstance(); if (seralizer instanceof ObjectSerializer) { return (ObjectSerializer) seralizer; } } catch (Throwable e) { // skip } } if (jsonType.asm() == false) { asm = false; } } Class<?> clazz = beanInfo.beanType; if (!Modifier.isPublic(beanInfo.beanType.getModifiers())) { return new JavaBeanSerializer(beanInfo); } boolean asm = this.asm; if (asm && asmFactory.classLoader.isExternalClass(clazz) || clazz == Serializable.class || clazz == Object.class) { asm = false; } if (asm && !ASMUtils.checkName(clazz.getSimpleName())) { asm = false; } if (asm) { for(FieldInfo fieldInfo : beanInfo.fields){ Field field = fieldInfo.field; if (field != null && !field.getType().equals(fieldInfo.fieldClass)) { asm = false; break; } Method method = fieldInfo.method; if (method != null && !method.getReturnType().equals(fieldInfo.fieldClass)) { asm = false; break; } JSONField annotation = fieldInfo.getAnnotation(); if (annotation == null) { continue; } if ((!ASMUtils.checkName(annotation.name())) // || annotation.format().length() != 0 || annotation.jsonDirect() || annotation.serializeUsing() != Void.class ) { asm = false; break; } } } if (asm) { try { ObjectSerializer asmSerializer = createASMSerializer(beanInfo); if (asmSerializer != null) { return asmSerializer; } } catch (ClassFormatError e) { // skip } catch (ClassCastException e) { // skip } catch (Throwable e) { throw new JSONException("create asm serializer error, class " + clazz, e); } } return new JavaBeanSerializer(beanInfo); } View Code
使用asmClassLoader加载动态类:
// 创建asmSerializer, 最后调用classloader加载类 private final JavaBeanSerializer createASMSerializer(SerializeBeanInfo beanInfo) throws Exception { JavaBeanSerializer serializer = asmFactory.createJavaBeanSerializer(beanInfo); for (int i = 0; i < serializer.sortedGetters.length; ++i) { FieldSerializer fieldDeser = serializer.sortedGetters[i]; Class<?> fieldClass = fieldDeser.fieldInfo.fieldClass; if (fieldClass.isEnum()) { ObjectSerializer fieldSer = this.getObjectWriter(fieldClass); if (!(fieldSer instanceof EnumSerializer)) { serializer.writeDirect = false; } } } return serializer; }
最后的代码报错是:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false),由于是写在动态生成的代码文件中,比较难查,解决问题已足够,不再深究。
理解这里的原因后,再来看问题,就简单多了,排除掉不支持转换的类或者使用其他方式获取想要的参数。
思考:如果让自己来设计框架,也需要考虑得更多;在用别人的框架的时候,也以一个开发者的角度考虑问题,如果不想考虑,可以直接参考其源码,发现其中的蹊跷;另外,测试一定是必不可少的,你可以借助测试部门,也可以自行测试,但是一定要考虑全面;最后,在做一些公用方法的变动时,一定不要太大意,宁可相信自己不无知,也不要相信代码一定不会出错,有条件情况下,尽可以使用try catch将其包裹,这样,在出问题的时候,也能迅速定位。
题外话:错误一定是会犯的,但是不要关键时候犯。