package net.csdn.jpa.enhancer; import javassist.CtClass; import javassist.CtField; import javassist.CtMethod; import javassist.NotFoundException; import javassist.bytecode.AccessFlag; import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.ConstPool; import javassist.bytecode.annotation.BooleanMemberValue; import net.csdn.ServiceFramwork; import net.csdn.annotation.association.NotMapping; import net.csdn.annotation.validate.Validate; import net.csdn.common.collect.Tuple; import net.csdn.common.logging.CSLogger; import net.csdn.common.logging.Loggers; import net.csdn.common.settings.Settings; import net.csdn.enhancer.BitEnhancer; import net.csdn.jpa.type.DBInfo; import net.csdn.jpa.type.DBType; import javax.persistence.Column; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import static net.csdn.common.collections.WowCollections.list; import static net.csdn.common.collections.WowCollections.map; import static net.csdn.enhancer.EnhancerHelper.createAnnotation; /** * BlogInfo: WilliamZhu * Date: 12-7-2 * Time: 下午8:41 */ public class PropertyEnhancer implements BitEnhancer { private Settings settings; private CSLogger logger = Loggers.getLogger(getClass()); public PropertyEnhancer(Settings settings) { this.settings = settings; } @Override public void enhance(CtClass ctClass) throws Exception { autoInjectProperty(ctClass); autoInjectGetSet(ctClass); } private void notMapping(CtClass ctClass, List<String> skipFields) { if (ctClass.hasAnnotation(NotMapping.class)) { try { NotMapping notMapping = (NotMapping) ctClass.getAnnotation(NotMapping.class); for (String str : notMapping.value()) { skipFields.add(str); } } catch (Exception e) { e.printStackTrace(); } } autoNotMapping(ctClass, skipFields); } //自动过滤掉 private void autoNotMapping(CtClass ctClass, List<String> skipFields) { CtField[] fields = ctClass.getDeclaredFields(); for (CtField ctField : fields) { guessNotMappingName(ctField, ManyToOne.class, skipFields); guessNotMappingName(ctField, OneToOne.class, skipFields); } } private void guessNotMappingName(CtField ctField, Class clzz, List<String> skipFields) { if (ctField.hasAnnotation(clzz)) { Method mappedBy = null; try { Object wow = ctField.getAnnotation(clzz); mappedBy = wow.getClass().getMethod("mappedBy"); String value = (String) mappedBy.invoke(wow); if (value == null || value.isEmpty()) { skipFields.add(ctField.getName() + "_id"); } } catch (Exception e) { if (mappedBy == null) { skipFields.add(ctField.getName() + "_id"); } } } } private void autoInjectProperty(CtClass ctClass) { //连接数据库,自动获取所有信息,然后添加属性 String entitySimpleName = ctClass.getSimpleName(); List<String> skipFields = list(); notMapping(ctClass, skipFields); try { DBType dbType = ServiceFramwork.injector.getInstance(DBType.class); DBInfo dbInfo = ServiceFramwork.injector.getInstance(DBInfo.class); Map<String, String> columns = dbInfo.tableColumns.get(entitySimpleName); for (String columnName : columns.keySet()) { String fieldName = columnName; String fieldType = columns.get(columnName); if (skipFields.contains(fieldName)) continue; //对定义过的属性略过 boolean pass = true; try { ctClass.getField(fieldName); } catch (Exception e) { pass = false; } if (pass) continue; ConstPool constPool = ctClass.getClassFile().getConstPool(); AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); CtField ctField = CtField.make(" private " + dbType.typeToJava(fieldType).v2() + " " + fieldName + " ;", ctClass); Tuple<Class, Map> tuple = dbType.dateType(fieldType, constPool); if (tuple != null) { createAnnotation(attr, tuple.v1(), tuple.v2()); } if (fieldName.equals("id")) { createAnnotation(attr, javax.persistence.Id.class, map()); createAnnotation(attr, javax.persistence.GeneratedValue.class, map()); } else { createAnnotation(attr, Column.class, map("nullable", new BooleanMemberValue(true, constPool))); } if (attr.getAnnotations().length > 0) { ctField.getFieldInfo().addAttribute(attr); } ctClass.addField(ctField); } } catch (Exception e) { e.printStackTrace(); } ctClass.defrost(); } boolean isFinal(CtField ctField) { return Modifier.isFinal(ctField.getModifiers()); } boolean isStatic(CtField ctField) { return Modifier.isStatic(ctField.getModifiers()); } private void autoInjectGetSet(CtClass ctClass) throws Exception { //hibernate 可能需要 setter/getter 方法,好吧 我们为它添加这些方法 for (CtField ctField : ctClass.getDeclaredFields()) { if (isFinal(ctField) || isStatic(ctField) || ctField.hasAnnotation(Validate.class)) continue; // Property name String propertyName = ctField.getName().substring(0, 1).toUpperCase() + ctField.getName().substring(1); String getter = "get" + propertyName; String setter = "set" + propertyName; try { CtMethod ctMethod = ctClass.getDeclaredMethod(getter); if (ctMethod.getParameterTypes().length > 0 || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a getter !"); } } catch (NotFoundException noGetter) { String code = "public " + ctField.getType().getName() + " " + getter + "() { return this." + ctField.getName() + "; }"; CtMethod getMethod = CtMethod.make(code, ctClass); getMethod.setModifiers(getMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(getMethod); } try { CtMethod ctMethod = ctClass.getDeclaredMethod(setter); if (ctMethod.getParameterTypes().length != 1 || !ctMethod.getParameterTypes()[0].equals(ctField.getType()) || Modifier.isStatic(ctMethod.getModifiers())) { throw new NotFoundException("it's not a setter !"); } } catch (NotFoundException noSetter) { CtMethod setMethod = CtMethod.make("public void " + setter + "(" + ctField.getType().getName() + " value) { this." + ctField.getName() + " = value; }", ctClass); setMethod.setModifiers(setMethod.getModifiers() | AccessFlag.SYNTHETIC); ctClass.addMethod(setMethod); } } ctClass.defrost(); } }