From bac9c5e02ee9c8fc67e4abe1d9612e5501d69dfc Mon Sep 17 00:00:00 2001 From: smallchill Date: Fri, 28 Dec 2018 16:32:12 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20=E4=BF=AE=E5=A4=8D=20BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springblade/core/log/model/LogApi.java | 4 - .../springblade/core/log/model/LogApiVo.java | 33 ++++ .../core/log/model/LogErrorVo.java | 33 ++++ .../core/log/model/LogUsualVo.java | 33 ++++ .../core/tool/support/BladeBeanCopier.java | 184 ++++++++++++++++++ .../springblade/core/tool/utils/BeanUtil.java | 49 ++++- 6 files changed, 329 insertions(+), 7 deletions(-) create mode 100644 blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java create mode 100644 blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java create mode 100644 blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java create mode 100644 blade-core-tool/src/main/java/org/springblade/core/tool/support/BladeBeanCopier.java diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java index e385e07..762da12 100644 --- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java +++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java @@ -100,10 +100,6 @@ public class LogApi implements Serializable { * 执行时间 */ private String time; - /** - * 异常信息 - */ - private String exception; /** * 创建人 diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java new file mode 100644 index 0000000..5262426 --- /dev/null +++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.core.log.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * LogApi视图实体类 + * + * @author smallchill + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class LogApiVo extends LogApi { + private static final long serialVersionUID = 1L; + + private String strId; + +} diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java new file mode 100644 index 0000000..437ffd2 --- /dev/null +++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.core.log.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * LogError视图实体类 + * + * @author smallchill + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class LogErrorVo extends LogError { + private static final long serialVersionUID = 1L; + + private String strId; + +} diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java new file mode 100644 index 0000000..a908997 --- /dev/null +++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.core.log.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * LogUsual视图实体类 + * + * @author smallchill + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class LogUsualVo extends LogUsual { + private static final long serialVersionUID = 1L; + + private String strId; + +} diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/support/BladeBeanCopier.java b/blade-core-tool/src/main/java/org/springblade/core/tool/support/BladeBeanCopier.java new file mode 100644 index 0000000..7b389a5 --- /dev/null +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/support/BladeBeanCopier.java @@ -0,0 +1,184 @@ +package org.springblade.core.tool.support; + +import org.springblade.core.tool.utils.BeanUtil; +import org.springframework.asm.ClassVisitor; +import org.springframework.asm.Type; +import org.springframework.cglib.core.*; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; +import java.util.HashMap; +import java.util.Map; + +/** + * spring cglib 魔改 + * + *

+ * 1. 支持链式 bean + * 2. 自定义的 BeanCopier 解决 spring boot 和 cglib ClassLoader classLoader 不一致的问题 + *

+ * + * @author L.cm + */ +public abstract class BladeBeanCopier { + private static final BeanCopierKey KEY_FACTORY = (BeanCopierKey) KeyFactory.create(BeanCopierKey.class); + private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter"); + private static final Type BEAN_COPIER = TypeUtils.parseType(BladeBeanCopier.class.getName()); + private static final Signature COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER}); + private static final Signature CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)"); + + interface BeanCopierKey { + Object newInstance(String source, String target, boolean useConverter); + } + + public static BladeBeanCopier create(Class source, Class target, boolean useConverter) { + return BladeBeanCopier.create(source, target, null, useConverter); + } + + public static BladeBeanCopier create(Class source, Class target, ClassLoader classLoader, boolean useConverter) { + Generator gen; + if (classLoader == null) { + gen = new Generator(); + } else { + gen = new Generator(classLoader); + } + gen.setSource(source); + gen.setTarget(target); + gen.setUseConverter(useConverter); + return gen.create(); + } + + abstract public void copy(Object from, Object to, Converter converter); + + public static class Generator extends AbstractClassGenerator { + private static final Source SOURCE = new Source(BladeBeanCopier.class.getName()); + private final ClassLoader classLoader; + private Class source; + private Class target; + private boolean useConverter; + + Generator() { + super(SOURCE); + this.classLoader = null; + } + + Generator(ClassLoader classLoader) { + super(SOURCE); + this.classLoader = classLoader; + } + + public void setSource(Class source) { + if (!Modifier.isPublic(source.getModifiers())) { + setNamePrefix(source.getName()); + } + this.source = source; + } + + public void setTarget(Class target) { + if (!Modifier.isPublic(target.getModifiers())) { + setNamePrefix(target.getName()); + } + + this.target = target; + } + + public void setUseConverter(boolean useConverter) { + this.useConverter = useConverter; + } + + @Override + protected ClassLoader getDefaultClassLoader() { + return target.getClassLoader(); + } + + @Override + protected ProtectionDomain getProtectionDomain() { + return ReflectUtils.getProtectionDomain(source); + } + + public BladeBeanCopier create() { + Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter); + return (BladeBeanCopier) super.create(key); + } + + @Override + public void generateClass(ClassVisitor v) { + Type sourceType = Type.getType(source); + Type targetType = Type.getType(target); + ClassEmitter ce = new ClassEmitter(v); + ce.begin_class(Constants.V1_2, + Constants.ACC_PUBLIC, + getClassName(), + BEAN_COPIER, + null, + Constants.SOURCE_FILE); + + EmitUtils.null_constructor(ce); + CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); + + // 2018.12.27 by L.cm 支持链式 bean + PropertyDescriptor[] getters = BeanUtil.getBeanGetters(source); + PropertyDescriptor[] setters = BeanUtil.getBeanSetters(target); + Map names = new HashMap<>(); + for (PropertyDescriptor getter : getters) { + names.put(getter.getName(), getter); + } + + Local targetLocal = e.make_local(); + Local sourceLocal = e.make_local(); + e.load_arg(1); + e.checkcast(targetType); + e.store_local(targetLocal); + e.load_arg(0); + e.checkcast(sourceType); + e.store_local(sourceLocal); + + for (int i = 0; i < setters.length; i++) { + PropertyDescriptor setter = setters[i]; + PropertyDescriptor getter = (PropertyDescriptor) names.get(setter.getName()); + if (getter != null) { + MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); + MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); + if (useConverter) { + Type setterType = write.getSignature().getArgumentTypes()[0]; + e.load_local(targetLocal); + e.load_arg(2); + e.load_local(sourceLocal); + e.invoke(read); + e.box(read.getSignature().getReturnType()); + EmitUtils.load_class(e, setterType); + e.push(write.getSignature().getName()); + e.invoke_interface(CONVERTER, CONVERT); + e.unbox_or_zero(setterType); + e.invoke(write); + } else if (compatible(getter, setter)) { + // 2018.12.27 by L.cm 支持链式 bean + e.load_local(targetLocal); + e.load_local(sourceLocal); + e.invoke(read); + e.invoke(write); + } + } + } + e.return_value(); + e.end_method(); + ce.end_class(); + } + + private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) { + // TODO: allow automatic widening conversions? + return setter.getPropertyType().isAssignableFrom(getter.getPropertyType()); + } + + @Override + protected Object firstInstance(Class type) { + return ReflectUtils.newInstance(type); + } + + @Override + protected Object nextInstance(Object instance) { + return instance; + } + } +} diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java index 2912f6c..a5811a4 100644 --- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/BeanUtil.java @@ -17,12 +17,16 @@ package org.springblade.core.tool.utils; import org.springblade.core.tool.support.BeanProperty; +import org.springblade.core.tool.support.BladeBeanCopier; import org.springframework.beans.BeansException; -import org.springframework.cglib.beans.BeanCopier; import org.springframework.cglib.beans.BeanGenerator; import org.springframework.cglib.beans.BeanMap; +import org.springframework.cglib.core.CodeGenerationException; import org.springframework.util.Assert; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -105,7 +109,7 @@ public class BeanUtil extends org.springframework.beans.BeanUtils { * @return T */ public static T copy(Object source, Class clazz) { - BeanCopier copier = BeanCopier.create(source.getClass(), clazz, false); + BladeBeanCopier copier = BladeBeanCopier.create(source.getClass(), clazz, false); T to = newInstance(clazz); copier.copy(source, to, null); @@ -121,7 +125,7 @@ public class BeanUtil extends org.springframework.beans.BeanUtils { * @param targetBean 需要赋值的对象 */ public static void copy(Object source, Object targetBean) { - BeanCopier copier = BeanCopier + BladeBeanCopier copier = BladeBeanCopier .create(source.getClass(), targetBean.getClass(), false); copier.copy(source, targetBean, null); @@ -197,4 +201,43 @@ public class BeanUtil extends org.springframework.beans.BeanUtils { return generator.create(); } + /** + * 获取 Bean 的所有 get方法 + * @param type 类 + * @return PropertyDescriptor数组 + */ + public static PropertyDescriptor[] getBeanGetters(Class type) { + return getPropertiesHelper(type, true, false); + } + + /** + * 获取 Bean 的所有 set方法 + * @param type 类 + * @return PropertyDescriptor数组 + */ + public static PropertyDescriptor[] getBeanSetters(Class type) { + return getPropertiesHelper(type, false, true); + } + + private static PropertyDescriptor[] getPropertiesHelper(Class type, boolean read, boolean write) { + try { + PropertyDescriptor[] all = BeanUtil.getPropertyDescriptors(type); + if (read && write) { + return all; + } else { + List properties = new ArrayList<>(all.length); + for (PropertyDescriptor pd : all) { + if (read && pd.getReadMethod() != null) { + properties.add(pd); + } else if (write && pd.getWriteMethod() != null) { + properties.add(pd); + } + } + return properties.toArray(new PropertyDescriptor[0]); + } + } catch (BeansException ex) { + throw new CodeGenerationException(ex); + } + } + }