예제 #1
0
  public static void patch(CtClass c, IPatcher patcher) throws Exception {
    treatClassToPatch(c);

    if (patcher != null) {
      patcher.initClass(c);
    }

    for (CtMethod m : c.getDeclaredMethods()) {
      boolean wasAbstract = false;
      String newBody = null;
      if (Modifier.isAbstract(m.getModifiers())) {
        m.setModifiers(m.getModifiers() - Modifier.ABSTRACT);
        wasAbstract = true;
      }
      if (patcher != null) {
        newBody = patcher.getNewBody(m);
      }
      if (newBody != null) {
        if (newBody.startsWith(AutomaticPatcher.INSERT_BEFORE)) {
          GwtPatcherUtils.insertBefore(
              m, newBody.substring(AutomaticPatcher.INSERT_BEFORE.length()));
        } else if (newBody.startsWith(AutomaticPatcher.INSERT_AFTER)) {
          GwtPatcherUtils.insertAfter(m, newBody.substring(AutomaticPatcher.INSERT_AFTER.length()));
        } else {
          GwtPatcherUtils.replaceImplementation(m, newBody);
        }
      } else if (wasAbstract) {
        if (patcher != null) {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by "
                  + patcher.getClass().getName()
                  + "\"); }");
        } else {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by any declared "
                  + IPatcher.class.getSimpleName()
                  + " instance\"); }");
        }
      }
    }

    if (patcher != null) {
      patcher.finalizeClass(c);
    }
  }
  private void autoInjectProperty(ModelClass modelClass) {

    // 连接数据库,自动获取所有信息,然后添加属性
    CtClass ctClass = modelClass.originClass;
    String entitySimpleName = ctClass.getSimpleName();
    List<String> skipFields = modelClass.notMappingColumns();

    try {
      DBType dbType = ServiceFramwork.injector.getInstance(DBType.class);
      DBInfo dbInfo = ServiceFramwork.injector.getInstance(DBInfo.class);

      Map<String, String> columns = dbInfo.tableColumns.get(entitySimpleName);
      if (columns == null) return;
      for (String columnName : columns.keySet()) {
        String fieldName = columnName;
        String fieldType = columns.get(columnName);
        if (skipFields.contains(fieldName)) continue;
        if (fieldName.equals("discriminator")) 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();
  }
예제 #3
0
  //    @Test
  public void ctClassName() throws NotFoundException {
    ClassPool pool = new ClassPool(true);

    CtClass ctClass = pool.get("java.lang.String");
    logger.info("ctClass:{}", ctClass);
    logger.info("ctClass:{}", ctClass.getName());
    logger.info("ctClass:{}", ctClass.getSimpleName());
  }
  private static boolean isThrowsSqlException(CtMethod method) {
    try {
      for (CtClass clazz : method.getExceptionTypes()) {
        if (clazz.getSimpleName().equals("SQLException")) {
          return true;
        }
      }
    } catch (NotFoundException e) {
      // fall thru
    }

    return false;
  }
예제 #5
0
  @Override
  public void enhanceThisClass(ApplicationClass applicationClass) throws Exception {

    final CtClass ctClass = makeClass(applicationClass);
    if (ctClass.isInterface()) {
      return;
    }
    if (ctClass.getName().endsWith(".package")) {
      return;
    }

    // Add a default constructor if needed
    try {
      boolean hasDefaultConstructor = false;
      for (CtConstructor constructor : ctClass.getDeclaredConstructors()) {
        if (constructor.getParameterTypes().length == 0) {
          hasDefaultConstructor = true;
          break;
        }
      }
      if (!hasDefaultConstructor && !ctClass.isInterface()) {
        CtConstructor defaultConstructor =
            CtNewConstructor.make("public " + ctClass.getSimpleName() + "() {}", ctClass);
        ctClass.addConstructor(defaultConstructor);
      }
    } catch (Exception e) {
      Logger.error(e, "Error in PropertiesEnhancer");
      throw new UnexpectedException("Error in PropertiesEnhancer", e);
    }

    if (isScala(applicationClass)) {
      // Temporary hack for Scala. Done.
      applicationClass.enhancedByteCode = ctClass.toBytecode();
      ctClass.defrost();
      return;
    }

    for (CtField ctField : ctClass.getDeclaredFields()) {
      try {

        if (isProperty(ctField)) {

          // 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) {

            // Créé le getter
            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);
          }

          if (!isFinal(ctField)) {
            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) {
              // Créé le setter
              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);
              createAnnotation(getAnnotations(setMethod), PlayPropertyAccessor.class);
            }
          }
        }

      } catch (Exception e) {
        Logger.error(e, "Error in PropertiesEnhancer");
        throw new UnexpectedException("Error in PropertiesEnhancer", e);
      }
    }

    // Add a default constructor if needed
    try {
      boolean hasDefaultConstructor = false;
      for (CtConstructor constructor : ctClass.getDeclaredConstructors()) {
        if (constructor.getParameterTypes().length == 0) {
          hasDefaultConstructor = true;
          break;
        }
      }
      if (!hasDefaultConstructor) {
        CtConstructor defaultConstructor = CtNewConstructor.defaultConstructor(ctClass);
        ctClass.addConstructor(defaultConstructor);
      }
    } catch (Exception e) {
      Logger.error(e, "Error in PropertiesEnhancer");
      throw new UnexpectedException("Error in PropertiesEnhancer", e);
    }

    // Intercept all fields access
    for (final CtBehavior ctMethod : ctClass.getDeclaredBehaviors()) {
      ctMethod.instrument(
          new ExprEditor() {

            @Override
            public void edit(FieldAccess fieldAccess) throws CannotCompileException {
              try {

                // Acces à une property ?
                if (isProperty(fieldAccess.getField())) {

                  // TODO : vérifier que c'est bien un champ d'une classe de l'application
                  // (fieldAccess.getClassName())

                  // Si c'est un getter ou un setter
                  String propertyName = null;
                  if (fieldAccess
                          .getField()
                          .getDeclaringClass()
                          .equals(ctMethod.getDeclaringClass())
                      || ctMethod
                          .getDeclaringClass()
                          .subclassOf(fieldAccess.getField().getDeclaringClass())) {
                    if ((ctMethod.getName().startsWith("get")
                            || (!isFinal(fieldAccess.getField())
                                && ctMethod.getName().startsWith("set")))
                        && ctMethod.getName().length() > 3) {
                      propertyName = ctMethod.getName().substring(3);
                      propertyName =
                          propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
                    }
                  }

                  // On n'intercepte pas le getter de sa propre property
                  if (propertyName == null || !propertyName.equals(fieldAccess.getFieldName())) {

                    String invocationPoint =
                        ctClass.getName()
                            + "."
                            + ctMethod.getName()
                            + ", line "
                            + fieldAccess.getLineNumber();

                    if (fieldAccess.isReader()) {

                      // Réécris l'accés en lecture à la property
                      fieldAccess.replace(
                          "$_ = ($r)play.classloading.enhancers.PropertiesEnhancer.FieldAccessor.invokeReadProperty($0, \""
                              + fieldAccess.getFieldName()
                              + "\", \""
                              + fieldAccess.getClassName()
                              + "\", \""
                              + invocationPoint
                              + "\");");

                    } else if (!isFinal(fieldAccess.getField()) && fieldAccess.isWriter()) {

                      // Réécris l'accés en ecriture à la property
                      fieldAccess.replace(
                          "play.classloading.enhancers.PropertiesEnhancer.FieldAccessor.invokeWriteProperty($0, \""
                              + fieldAccess.getFieldName()
                              + "\", "
                              + fieldAccess.getField().getType().getName()
                              + ".class, $1, \""
                              + fieldAccess.getClassName()
                              + "\", \""
                              + invocationPoint
                              + "\");");
                    }
                  }
                }

              } catch (Exception e) {
                throw new UnexpectedException("Error in PropertiesEnhancer", e);
              }
            }
          });
    }

    // Done.
    applicationClass.enhancedByteCode = ctClass.toBytecode();
    ctClass.defrost();
  }
  @Override
  public void enhanceThisClass(ApplicationClass applicationClass) throws Exception {
    CtClass ctClass = makeClass(applicationClass);
    String entityName = ctClass.getName();
    Logger.debug("Enhance class " + entityName);

    // Only enhance Neo4jModel classes.
    if (!ctClass.subtypeOf(classPool.get("play.modules.neo4j.model.Neo4jModel"))) {
      return;
    }

    // Add a default constructor if needed
    try {
      for (CtConstructor constructor : ctClass.getDeclaredConstructors()) {
        if (constructor.getParameterTypes().length == 0) {
          ctClass.removeConstructor(constructor);
        }
        if (constructor.getParameterTypes().length == 1
            && constructor.getParameterTypes()[0].getClass().isInstance(Node.class)) {
          ctClass.removeConstructor(constructor);
        }
      }
      if (!ctClass.isInterface()) {
        Logger.debug("Adding default constructor");
        CtConstructor defaultConstructor =
            CtNewConstructor.make("public " + ctClass.getSimpleName() + "() { super();}", ctClass);
        ctClass.addConstructor(defaultConstructor);
      }
    } catch (Exception e) {
      Logger.error(e, "Error in PropertiesEnhancer");
      throw new UnexpectedException("Error in PropertiesEnhancer", e);
    }

    // for all field, we add getter / setter
    for (CtField ctField : ctClass.getDeclaredFields()) {
      try {
        // Property name
        String propertyName =
            ctField.getName().substring(0, 1).toUpperCase() + ctField.getName().substring(1);
        String getter = "get" + propertyName;
        String setter = "set" + propertyName;

        Logger.debug("Field " + ctField.getName() + " is a property ?");
        if (isProperty(ctField)) {
          Logger.debug("true");

          // ~~~~~~~~~
          // GETTER
          // ~~~~~~~
          try {
            CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
            if (!ctMethod.getName().equalsIgnoreCase("getShouldBeSave")) {
              ctClass.removeMethod(ctMethod);
              throw new NotFoundException("it's not a true getter !");
            }
          } catch (NotFoundException noGetter) {
            // create getter
            Logger.debug("Adding getter " + getter + " for class " + entityName);
            // @formatter:off
            String code =
                "public "
                    + ctField.getType().getName()
                    + " "
                    + getter
                    + "() {"
                    + "if(this.shouldBeSave == Boolean.FALSE && this.node != null){"
                    + "return (("
                    + ctField.getType().getName()
                    + ") play.modules.neo4j.util.Binder.bindFromNeo4jFormat(this.node.getProperty(\""
                    + ctField.getName()
                    + "\", null),"
                    + ctField.getType().getName()
                    + ".class ));"
                    + "}else{"
                    + "return "
                    + ctField.getName()
                    + ";"
                    + "}"
                    + "}";
            // @formatter:on
            Logger.debug(code);
            CtMethod getMethod = CtMethod.make(code, ctClass);
            ctClass.addMethod(getMethod);
          }

          // ~~~~~~~~~
          // SETTER
          // ~~~~~~~
          try {
            CtMethod ctMethod = ctClass.getDeclaredMethod(setter);
            if (ctMethod.getParameterTypes().length != 1
                || !ctMethod.getParameterTypes()[0].equals(ctField.getType())
                || Modifier.isStatic(ctMethod.getModifiers())
                || hasPlayPropertiesAccessorAnnotation(ctMethod)) {
              if (hasPlayPropertiesAccessorAnnotation(ctMethod)) {
                ctClass.removeMethod(ctMethod);
              }
              throw new NotFoundException("it's not a true setter !");
            }
          } catch (NotFoundException noSetter) {
            // create setter
            Logger.debug("Adding setter " + setter + " for class " + entityName);
            // @formatter:off
            String code =
                "public void "
                    + setter
                    + "("
                    + ctField.getType().getName()
                    + " value) { "
                    + "this."
                    + ctField.getName()
                    + " = value;"
                    + "this.shouldBeSave = Boolean.TRUE;"
                    + "}";
            // formatter:on
            CtMethod setMethod = CtMethod.make(code, ctClass);
            Logger.debug(code);
            ctClass.addMethod(setMethod);
          }
        } else {
          // ~~~~~~~~~
          // GETTER for neo4j relation property
          // ~~~~~~~
          if (hasNeo4jRelationAnnotation(ctField)) {
            // test for related annotation
            Neo4jRelatedTo relatedTo = getRelatedAnnotation(ctField);
            if (relatedTo != null) {
              CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
              ctClass.removeMethod(ctMethod);
              String code;
              if (relatedTo.lazy()) {
                // @formatter:off
                code =
                    "public "
                        + ctField.getType().getName()
                        + " "
                        + getter
                        + "() {"
                        + "if(this."
                        + ctField.getName()
                        + " == null){"
                        + "java.lang.reflect.Field field = this.getClass().getField(\""
                        + ctField.getName()
                        + "\");"
                        + "this."
                        + ctField.getName()
                        + "=play.modules.neo4j.relationship.Neo4jRelationFactory.getModelsFromRelation(\""
                        + relatedTo.value()
                        + "\", \""
                        + relatedTo.direction()
                        + "\", field, this.node);"
                        + "}"
                        + "return "
                        + ctField.getName()
                        + ";"
                        + "}";
                // @formatter:on
              } else {
                // @formatter:off
                code =
                    "public "
                        + ctField.getType().getName()
                        + " "
                        + getter
                        + "() {"
                        + "return "
                        + ctField.getName()
                        + ";"
                        + "}";
                // @formatter:on
              }
              Logger.debug(code);
              CtMethod method = CtMethod.make(code, ctClass);
              ctClass.addMethod(method);
            }
            // test for unique relation annotation
            Neo4jUniqueRelation uniqueRelation = getUniqueRelationAnnotation(ctField);
            if (uniqueRelation != null) {
              CtMethod ctMethod = ctClass.getDeclaredMethod(getter);
              ctClass.removeMethod(ctMethod);
              String code;
              // @formatter:off
              code =
                  "public "
                      + ctField.getType().getName()
                      + " "
                      + getter
                      + "() {"
                      + "return ("
                      + ctField.getType().getName()
                      + ")"
                      + ctField.getName()
                      + ";"
                      + "}";
              // @formatter:on
              Logger.debug(code);
              CtMethod method = CtMethod.make(code, ctClass);
              ctClass.addMethod(method);
            }
          }
        }
      } catch (Exception e) {
        Logger.error(e, "Error in PropertiesEnhancer");
        throw new UnexpectedException("Error in PropertiesEnhancer", e);
      }
    }

    // Adding getByKey() method
    Logger.debug("Adding getByKey() method for class " + entityName);
    // @formatter:off
    String codeGetByKey =
        "public static play.modules.neo4j.model.Neo4jModel getByKey(Long key) throws play.modules.neo4j.exception.Neo4jException {"
            + "return ("
            + entityName
            + ")_getByKey(key, \""
            + entityName
            + "\");"
            + "}";
    // @formatter:on
    Logger.debug(codeGetByKey);
    CtMethod getByKeyMethod = CtMethod.make(codeGetByKey, ctClass);
    ctClass.addMethod(getByKeyMethod);

    // ~~~~~~~~~~~~~~~
    // Adding findAll() method
    // @formatter:off
    String codeFindAll =
        "public static java.util.List findAll() {"
            + "return "
            + entityName
            + "._findAll(\""
            + entityName
            + "\");"
            + "}";
    // @formatter:on
    Logger.debug(codeFindAll);
    CtMethod findAllMethod = CtMethod.make(codeFindAll, ctClass);
    ctClass.addMethod(findAllMethod);

    // ~~~~~~~~~~~~~~~
    // Adding queryIndex() method
    // @formatter:off
    String queryIndex =
        "public static java.util.List queryIndex(String indexname, String query) {"
            + "return "
            + entityName
            + "._queryIndex(indexname, query);"
            + "}";
    // @formatter:on
    Logger.debug(queryIndex);
    CtMethod queryIndexMethod = CtMethod.make(queryIndex, ctClass);
    ctClass.addMethod(queryIndexMethod);

    // Done.
    applicationClass.enhancedByteCode = ctClass.toBytecode();
    ctClass.defrost();
  }
      private URL computeResourceURL(Method method) throws NotFoundException, URISyntaxException {
        List<ResourceFileEntry> filesSimpleNames = new ArrayList<ResourceFileEntry>();
        boolean computeExtensions = false;
        CtMethod m = ctClass.getMethod(method.getName(), getDescriptor(method));
        MethodInfo minfo = m.getMethodInfo2();
        AnnotationsAttribute attr =
            (AnnotationsAttribute) minfo.getAttribute(AnnotationsAttribute.invisibleTag);
        if (attr != null) {
          Annotation an = attr.getAnnotation(Source.class.getName());
          if (an != null) {
            MemberValue[] mvArray = ((ArrayMemberValue) an.getMemberValue("value")).getValue();
            if (mvArray != null) {
              for (MemberValue mv : mvArray) {
                StringMemberValue smv = (StringMemberValue) mv;
                filesSimpleNames.add(new ResourceFileEntry(smv.getValue(), m));
              }
            }
          }
        }

        if (filesSimpleNames.isEmpty()) {
          // no @Source annotation detected
          filesSimpleNames.add(new ResourceFileEntry(method.getName(), m));
          computeExtensions = true;
        }

        List<URL> existingFiles = new ArrayList<URL>();

        for (ResourceFileEntry resourceEntry : filesSimpleNames) {
          String resourceName = resourceEntry.resourceName;
          CtClass declaringClass = resourceEntry.resourceMethod.getDeclaringClass();
          String baseDir = declaringClass.getPackageName().replaceAll("\\.", "/") + "/";
          String fileName =
              (resourceName.startsWith(baseDir)) ? resourceName : baseDir + resourceName;

          if (computeExtensions) {
            String[] extensions = getResourceDefaultExtensions(method);

            for (String extension : extensions) {
              String possibleFile = fileName + extension;
              URL url = GwtPatcher.class.getClassLoader().getResource(possibleFile);
              if (url != null) {
                existingFiles.add(url);
              }
            }
          } else {
            URL url = GwtPatcher.class.getClassLoader().getResource(fileName);
            if (url != null) {
              existingFiles.add(url);
            }
          }
        }

        if (existingFiles.isEmpty()) {
          throw new RuntimeException(
              "No resource file found for method "
                  + ctClass.getSimpleName()
                  + "."
                  + method.getName()
                  + "()");
        } else if (existingFiles.size() > 1) {
          throw new RuntimeException(
              "Too many resource files found for method "
                  + ctClass.getSimpleName()
                  + "."
                  + method.getName()
                  + "()");
        }

        return existingFiles.get(0);
      }
예제 #8
0
  /**
   * Given a bean-style interface, generate an instance of the interface by implementing getters and
   * setters for each property. It will also add implementations to support the {@link
   * SupportsRdfId} interface and generate simple, default equals, toString and hashCode methods.
   *
   * <p>If there are other non-bean style (getter and/or setter's for properties) methods on the
   * interface, this will likely fail to generate the instance.
   *
   * @param theInterface the interface to build an instance of
   * @param <T> the type of the interface
   * @return New dynamically generated bytecode of a class that implements the given interface.
   * @throws Exception if there is an error while generating the bytecode of the new class.
   */
  public static synchronized <T> Class<T> generateInstanceClass(Class<T> theInterface)
      throws Exception {
    processedMethods.clear();

    // TODO: can we use some sort of template language for this?

    ClassPool aPool = ClassPool.getDefault();

    aPool.appendClassPath(new LoaderClassPath(theInterface.getClassLoader()));

    CtClass aInterface = aPool.get(theInterface.getName());
    CtClass aSupportsRdfIdInterface = aPool.get(SupportsRdfId.class.getName());
    CtClass aEmpireGeneratedInterface = aPool.get(EmpireGenerated.class.getName());

    if (!Arrays.asList(aInterface.getInterfaces()).contains(aSupportsRdfIdInterface)
        && !SupportsRdfId.class.isAssignableFrom(theInterface)) {
      throw new IllegalArgumentException(
          "Class '"
              + theInterface.getName()
              + "' does not implement SupportsRdfId, cannot generate Empire suitable implementation.");
    }

    String aName = aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl";
    CtClass aClass = null;

    try {
      //  i had a good reason for doing this, but i dont remember what it is.  when i do, i'll
      // explain it here =)

      aClass = aPool.get(aName);
      return (Class<T>) BeanReflectUtil.loadClass(aName);
    } catch (NotFoundException e) {
      aClass =
          aPool.makeClass(
              aInterface.getPackageName() + ".impl." + aInterface.getSimpleName() + "Impl");
    } catch (ClassNotFoundException e) {
      throw new Exception("Previously created class cannot be loaded.", e);
    }

    if (aClass.isFrozen()) {
      aClass.defrost();
    }

    if (aInterface.isInterface()) {
      aClass.addInterface(aInterface);
    } else {
      aClass.setSuperclass(aInterface);
    }

    aClass.addInterface(aSupportsRdfIdInterface);
    aClass.addInterface(aEmpireGeneratedInterface);

    CtField aInterfaceField =
        new CtField(aPool.get(Class.class.getName()), "mInterfaceClass", aClass);
    aClass.addField(
        aInterfaceField, CtField.Initializer.byExpr(theInterface.getName() + ".class;"));

    CtField aAllTriplesField = new CtField(aPool.get(Graph.class.getName()), "mAllTriples", aClass);
    aClass.addField(
        aAllTriplesField, CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();"));

    CtField aInstanceTriplesField =
        new CtField(aPool.get(Graph.class.getName()), "mInstanceTriples", aClass);
    aClass.addField(
        aInstanceTriplesField,
        CtField.Initializer.byExpr("new com.clarkparsia.openrdf.ExtGraph();"));

    aClass.addConstructor(CtNewConstructor.defaultConstructor(aClass));

    generateMethods(theInterface, aPool, aClass);
    generateMethodsForSuperInterfaces(theInterface, aPool, aClass);

    CtField aIdField = new CtField(aPool.get(SupportsRdfId.class.getName()), "supportsId", aClass);
    aClass.addField(
        aIdField,
        CtField.Initializer.byExpr("new com.clarkparsia.empire.annotation.SupportsRdfIdImpl();"));

    if (!hasMethod(aClass, "getRdfId")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public com.clarkparsia.empire.SupportsRdfId.RdfKey getRdfId() { return supportsId.getRdfId(); } ",
              aClass));
    }

    if (!hasMethod(aClass, "setRdfId")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setRdfId(com.clarkparsia.empire.SupportsRdfId.RdfKey theURI) { supportsId.setRdfId(theURI); } ",
              aClass));
    }

    if (!hasMethod(aClass, "getAllTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public org.openrdf.model.Graph getAllTriples() { return mAllTriples; } ", aClass));
    }

    if (!hasMethod(aClass, "setAllTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setAllTriples(org.openrdf.model.Graph theGraph) { mAllTriples = theGraph; } ",
              aClass));
    }

    if (!hasMethod(aClass, "getInstanceTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public org.openrdf.model.Graph getInstanceTriples() { return mInstanceTriples; } ",
              aClass));
    }

    if (!hasMethod(aClass, "setInstanceTriples")) {
      aClass.addMethod(
          CtNewMethod.make(
              "public void setInstanceTriples(org.openrdf.model.Graph theGraph) { mInstanceTriples = theGraph; } ",
              aClass));
    }

    String equalsMethodBody =
        "public boolean equals(Object theObj) {\n"
            + "  if (theObj == this) return true;\n"
            + "  if (!(theObj instanceof com.clarkparsia.empire.SupportsRdfId)) return false;\n"
            + "  if (!(mInterfaceClass.isAssignableFrom(theObj.getClass()))) return false;\n"
            + "  return getRdfId().equals( ((com.clarkparsia.empire.SupportsRdfId) theObj).getRdfId()) && super.equals(theObj);\n"
            + "}\n";

    aClass.addMethod(CtNewMethod.make(equalsMethodBody, aClass));

    if (theInterface.isInterface()) {
      aClass.addMethod(
          CtNewMethod.make(
              "public String toString() { return getRdfId() != null ? getRdfId().toString() : super.toString(); } ",
              aClass));
      aClass.addMethod(
          CtNewMethod.make(
              "public int hashCode() { return getRdfId() != null ? getRdfId().hashCode() : 0; } ",
              aClass));
    }

    aClass.freeze();

    Class<T> aResult = (Class<T>) aClass.toClass();

    try {
      // make sure this is a valid class, that is, we can create instances of it!
      aResult.newInstance();
    } catch (Exception ex) {
      // TODO: log this?
      throw ex;
    }

    return aResult;
  }
  /*
     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();
  }
  private void enhanceModelMethods(CtClass ctClass) throws Exception {
    String entityName = ctClass.getName();
    String simpleEntityName = ctClass.getSimpleName();

    // count
    CtMethod count =
        CtMethod.make(
            "public static long count() { return getJPAContext().jpql().count(\""
                + entityName
                + "\"); }",
            ctClass);
    ctClass.addMethod(count);

    // count2
    CtMethod count2 =
        CtMethod.make(
            "public static long count(String query, Object[] params) { return  getJPAContext().jpql().count(\""
                + entityName
                + "\", query, params); }",
            ctClass);
    ctClass.addMethod(count2);

    // findAll
    CtMethod findAll =
        CtMethod.make(
            "public static java.util.List findAll() { return  getJPAContext().jpql().findAll(\""
                + entityName
                + "\"); }",
            ctClass);
    ctClass.addMethod(findAll);

    // findById
    CtMethod findById =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPABase findById(Object id) { return  getJPAContext().jpql().findById("
                + entityName
                + ".class, id); }",
            ctClass);
    ctClass.addMethod(findById);

    // find
    CtMethod find =
        CtMethod.make(
            "public static net.csdn.jpa.model.Model.JPAQuery find(String query, Object[] params) { return  getJPAContext().jpql().find(\""
                + entityName
                + "\", query, params); }",
            ctClass);
    ctClass.addMethod(find);

    // find
    CtMethod find2 =
        CtMethod.make(
            "public static net.csdn.jpa.model.Model.JPAQuery find() { return  getJPAContext().jpql().find(\""
                + entityName
                + "\"); }",
            ctClass);
    ctClass.addMethod(find2);

    // all
    CtMethod all =
        CtMethod.make(
            "public static net.csdn.jpa.model.Model.JPAQuery all() { return  getJPAContext().jpql().all(\""
                + entityName
                + "\"); }",
            ctClass);
    ctClass.addMethod(all);

    // delete
    CtMethod delete =
        CtMethod.make(
            "public static int delete(String query, Object[] params) { return  getJPAContext().jpql().delete(\""
                + entityName
                + "\", query, params); }",
            ctClass);
    ctClass.addMethod(delete);

    // deleteAll
    CtMethod deleteAll =
        CtMethod.make(
            "public static int deleteAll() { return  getJPAContext().jpql().deleteAll(\""
                + entityName
                + "\"); }",
            ctClass);
    ctClass.addMethod(deleteAll);

    // findOneBy
    CtMethod findOneBy =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPABase findOneBy(String query, Object[] params) { return  getJPAContext().jpql().findOneBy(\""
                + entityName
                + "\", query, params); }",
            ctClass);
    ctClass.addMethod(findOneBy);

    // create
    CtMethod create =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPABase create(java.util.Map params) { return  getJPAContext().jpql().create("
                + entityName
                + ".class, params); }",
            ctClass);
    ctClass.addMethod(create);

    // where
    CtMethod where =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL where(String cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").where(cc);}",
            ctClass);
    ctClass.addMethod(where);

    // where2
    CtMethod where2 =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL where(String cc,java.util.Map params){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").where(cc,params);}",
            ctClass);
    ctClass.addMethod(where2);

    // select
    CtMethod select =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL select(String cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").select(cc);}",
            ctClass);
    ctClass.addMethod(select);
    // joins
    CtMethod joins =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL joins(String cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").joins(cc);}",
            ctClass);
    ctClass.addMethod(joins);

    // order
    CtMethod order =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL order(String cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").order(cc);}",
            ctClass);
    ctClass.addMethod(order);
    // limit
    CtMethod limit =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL limit(int cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").limit(cc);}",
            ctClass);
    ctClass.addMethod(limit);
    // offset
    CtMethod offset =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPQL offset(int cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").offset(cc);}",
            ctClass);
    ctClass.addMethod(offset);

    CtMethod findWithSingleId =
        CtMethod.make(
            "public static net.csdn.jpa.model.JPABase  find(Integer cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").find(cc);}",
            ctClass);
    ctClass.addMethod(findWithSingleId);

    CtMethod findWithMultiId =
        CtMethod.make(
            "public static java.util.List find(java.util.List cc){return getJPAContext().jpql(\""
                + simpleEntityName
                + "\").find(cc);}",
            ctClass);
    ctClass.addMethod(findWithMultiId);

    ctClass.defrost();
  }