private void enhanceJPACallback(CtClass ctClass, CtMethod method, Class anno) throws Exception {
    if (method.hasAnnotation(anno)) {
      CtMethod ctMethod =
          CtMethod.make(
              format(
                  "public void {}() {\n"
                      + "        net.csdn.jpa.context.JPAContext jpaContext = getJPAConfig().reInitJPAContext();\n"
                      + "        try {\n"
                      + "            {}();\n"
                      + "            getJPAConfig().getJPAContext().closeTx(false);\n"
                      + "        } catch (Exception e) {\n"
                      + "            getJPAConfig().getJPAContext().closeTx(true);\n"
                      + "        } finally {\n"
                      + "            getJPAConfig().setJPAContext(jpaContext);\n"
                      + "        }\n"
                      + "    }",
                  "$_" + method.getName(),
                  method.getName()),
              ctClass);

      ctClass.addMethod(ctMethod);
      AnnotationsAttribute annotationsAttribute = EnhancerHelper.getAnnotations(ctMethod);
      EnhancerHelper.createAnnotation(annotationsAttribute, callback_classes.get(anno));
    }
  }
 private void setManyToManyHint(CtField ctField) {
   AnnotationsAttribute annotationsAttribute = EnhancerHelper.getAnnotations(ctField);
   EnhancerHelper.createAnnotation(annotationsAttribute, ManyToManyHint.class);
 }
  /*
     Hibernate 的关联关系太复杂了。要么你区分控制端和被控制端。要么你必须在使用的时候将两端都设置好关联关系。
     对于mappedBy也是一个无语的设计。为什么我要通过它来区分控制端?
  */
  @Override
  public void enhance(CtClass ctClass) throws Exception {
    CtField[] fields = ctClass.getDeclaredFields();
    //        String entityListener = "javax.persistence.EntityListeners";

    //        if (ctClass.hasAnnotation(EntityCallback.class)) {
    //            EntityCallback entityListeners = (EntityCallback)
    // ctClass.getAnnotation(EntityCallback.class);
    //            String clzzName = entityListeners.value();
    //            CtClass clzz = ServiceFramwork.classPool.get(clzzName);
    //            enhanceJPACallback(clzz);
    //            AnnotationsAttribute annotationsAttribute =
    // EnhancerHelper.getAnnotations(ctClass);
    //            ArrayMemberValue arrayMemberValue = new
    // ArrayMemberValue(annotationsAttribute.getConstPool());
    //            ClassMemberValue[] clzzes = new ClassMemberValue[]{new ClassMemberValue(clzzName,
    // annotationsAttribute.getConstPool())};
    //            arrayMemberValue.setValue(clzzes);
    //            EnhancerHelper.createAnnotation(annotationsAttribute, EntityListeners.class,
    // map("value", arrayMemberValue));
    //
    //        } else {
    //
    //        }

    enhanceJPACallback(ctClass);

    for (CtField ctField : fields) {

      if (EnhancerHelper.hasAnnotation(ctField, "javax.persistence.OneToOne")) {
        DBInfo dbInfo = ServiceFramwork.injector.getInstance(DBInfo.class);
        Map<String, String> columns = dbInfo.tableColumns.get(ctClass.getSimpleName());
        String clzzName = findAssociatedClassName(ctField);
        CtField mappedByField = findAssociatedField(ctClass, clzzName);
        if (!columns.containsKey(ctField.getName() + "_id")) {
          setMappedBy(ctField, mappedByField.getName(), "OneToOne");

        } else {
          setMappedBy(mappedByField, mappedByField.getName(), "OneToOne");
        }
        setCascad(mappedByField, "OneToOne");
        setCascad(ctField, "OneToOne");

        String mappedByClassName = clzzName;
        String mappedByFieldName = mappedByField.getName();

        findAndRemoveMethod(ctClass, ctField, mappedByClassName);
        findAndRemoveMethod(ctClass, ctField.getName());

        CtMethod wow =
            CtMethod.make(
                format(
                    "public net.csdn.jpa.association.Association {}() {"
                        + "net.csdn.jpa.association.Association obj = new net.csdn.jpa.association.Association(this,\"{}\",\"{}\",\"{}\");return obj;"
                        + "    }",
                    ctField.getName(),
                    ctField.getName(),
                    mappedByFieldName,
                    "javax.persistence.OneToOne"),
                ctClass);
        ctClass.addMethod(wow);

        CtMethod wow2 =
            CtMethod.make(
                format(
                    "public {} {}({} obj) {"
                        + "        this.attr(\"{}\",obj);"
                        + "        obj.attr(\"{}\",this);"
                        + "        return this;"
                        + "    }",
                    ctClass.getName(),
                    ctField.getName(),
                    mappedByClassName,
                    ctField.getName(),
                    mappedByFieldName),
                ctClass);
        ctClass.addMethod(wow2);
      }

      if (EnhancerHelper.hasAnnotation(ctField, "javax.persistence.OneToMany")) {

        String clzzName = findAssociatedClassName(ctField);

        String mappedByFieldName = findAssociatedFieldName(ctClass, clzzName);
        String mappedByClassName = ctClass.getName();

        // 如果没有设置mappedBy我们帮他设置吧
        setMappedBy(ctField, mappedByFieldName, "OneToMany");
        setCascad(ctField, "OneToMany");

        findAndRemoveMethod(ctClass, ctField, mappedByClassName);
        findAndRemoveMethod(ctClass, ctField.getName());
        String propertyName =
            mappedByFieldName.substring(0, 1).toUpperCase() + mappedByFieldName.substring(1);
        String getter = "set" + propertyName;

        CtMethod wow =
            CtMethod.make(
                format(
                    "public net.csdn.jpa.association.Association {}() {"
                        + "net.csdn.jpa.association.Association obj = new net.csdn.jpa.association.Association(this,\"{}\",\"{}\",\"{}\");return obj;"
                        + "    }",
                    ctField.getName(),
                    ctField.getName(),
                    mappedByFieldName,
                    "javax.persistence.OneToMany"),
                ctClass);
        ctClass.addMethod(wow);

        CtMethod wow2 =
            CtMethod.make(
                format(
                    "public {} {}({} obj) {"
                        + "        this.{}.add(obj);"
                        + "        obj.{}(this);"
                        + "        return this;"
                        + "    }",
                    ctClass.getName(),
                    ctField.getName(),
                    clzzName,
                    ctField.getName(),
                    getter),
                ctClass);
        ctClass.addMethod(wow2);
      }

      if (EnhancerHelper.hasAnnotation(ctField, "javax.persistence.ManyToOne")) {

        String clzzName = ctField.getType().getName();

        String mappedByFieldName = findAssociatedFieldName(ctClass, clzzName);
        String mappedByClassName = ctClass.getName();

        // 默认设置为cascade = CascadeType.PERSIST
        setCascad(ctField, "ManyToOne");

        findAndRemoveMethod(ctClass, ctField, mappedByClassName);
        findAndRemoveMethod(ctClass, ctField.getName());
        String propertyName =
            mappedByFieldName.substring(0, 1).toUpperCase() + mappedByFieldName.substring(1);
        String getter = "get" + propertyName;

        CtMethod wow =
            CtMethod.make(
                format(
                    "public net.csdn.jpa.association.Association {}() {"
                        + "net.csdn.jpa.association.Association obj = new net.csdn.jpa.association.Association(this,\"{}\",\"{}\",\"{}\");return obj;"
                        + "    }",
                    ctField.getName(),
                    ctField.getName(),
                    mappedByFieldName,
                    "javax.persistence.ManyToOne"),
                ctClass);
        ctClass.addMethod(wow);

        CtMethod wow2 =
            CtMethod.make(
                format(
                    "public {} {}({} obj) {"
                        + "        this.{} = obj;"
                        + "        obj.{}().add(this);"
                        + "        return this;"
                        + "    }",
                    ctClass.getName(),
                    ctField.getName(),
                    clzzName,
                    ctField.getName(),
                    getter),
                ctClass);
        ctClass.addMethod(wow2);
      }
      if (EnhancerHelper.hasAnnotation(ctField, "javax.persistence.ManyToMany")) {

        String clzzName = findAssociatedClassName(ctField);

        String mappedByFieldName = findAssociatedFieldName(ctClass, clzzName);
        String mappedByClassName = ctClass.getName();

        CtField other = findAssociatedField(ctClass, clzzName);

        DBInfo dbInfo = ServiceFramwork.injector.getInstance(DBInfo.class);
        String otherClassSimpleName =
            findAssociatedClass(ctClass.getClassPool(), ctField).getSimpleName();

        String maybeTable1 = ctClass.getSimpleName() + "_" + otherClassSimpleName;
        String maybeTable2 = otherClassSimpleName + "_" + ctClass.getSimpleName();
        String finalTableName = dbInfo.tableNames.contains(maybeTable1) ? maybeTable1 : maybeTable2;
        setCascad(ctField, "ManyToMany");
        boolean isMaster = false;
        if (!ctField.hasAnnotation(ManyToManyHint.class)) {
          if (dbInfo.tableNames.contains(maybeTable1)) {
            setMappedBy(other, ctField.getName(), "ManyToMany");
            isMaster = true;
            finalTableName = maybeTable1;
          }

          if (dbInfo.tableNames.contains(maybeTable2)) {
            setMappedBy(ctField, mappedByFieldName, "ManyToMany");
            finalTableName = maybeTable2;
          }
          setManyToManyHint(other);
        }

        findAndRemoveMethod(ctClass, ctField, mappedByClassName);
        findAndRemoveMethod(ctClass, ctField.getName());
        String propertyName =
            mappedByFieldName.substring(0, 1).toUpperCase() + mappedByFieldName.substring(1);
        String getter = "get" + propertyName;

        CtMethod wow =
            CtMethod.make(
                format(
                    "public net.csdn.jpa.association.Association {}() {"
                        + "net.csdn.jpa.association.Association obj = new net.csdn.jpa.association.Association(this,\"{}\",\"{}\",\"{}\",\"{}\",\"{}\");return obj;"
                        + "    }",
                    ctField.getName(),
                    ctField.getName(),
                    mappedByFieldName,
                    "javax.persistence.ManyToMany",
                    finalTableName,
                    isMaster),
                ctClass);
        ctClass.addMethod(wow);

        CtMethod wow2 =
            CtMethod.make(
                format(
                    "public {} {}({} obj) {"
                        + "        {}.add(obj);"
                        + "        obj.{}().add(this);"
                        + "        return this;"
                        + "    }",
                    ctClass.getName(),
                    ctField.getName(),
                    clzzName,
                    ctField.getName(),
                    getter),
                ctClass);
        ctClass.addMethod(wow2);
      }
    }
    ctClass.defrost();
  }