private MethodMetadata methodExists(
     JavaSymbolName methodName, List<AnnotatedJavaType> paramTypes) {
   // We have no access to method parameter information, so we scan by name alone and treat any
   // match as authoritative
   // We do not scan the superclass, as the caller is expected to know we'll only scan the current
   // class
   for (MethodMetadata method : governorTypeDetails.getDeclaredMethods()) {
     if (method.getMethodName().equals(methodName)
         && method.getParameterTypes().equals(paramTypes)) {
       // Found a method of the expected name; we won't check method parameters though
       return method;
     }
   }
   return null;
 }
 private void doModification(final MethodMetadata method, final CustomData customData) {
   MemberHoldingTypeDetails memberHoldingTypeDetails =
       memberHoldingTypeDetailsMap.get(method.getDeclaredByMetadataId());
   if (memberHoldingTypeDetails != null) {
     MethodMetadata matchedMethod =
         memberHoldingTypeDetails.getMethod(
             method.getMethodName(),
             AnnotatedJavaType.convertFromAnnotatedJavaTypes(method.getParameterTypes()));
     if (matchedMethod != null
         && !matchedMethod.getCustomData().keySet().containsAll(customData.keySet())) {
       TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails);
       typeDetailsBuilder.addDataToMethod(method, customData);
       changed = true;
     }
   }
 }
 public void addDataToMethod(final MethodMetadata replacement, final CustomData customData) {
   // If the MIDs don't match then the proposed can't be a replacement
   if (!replacement.getDeclaredByMetadataId().equals(getDeclaredByMetadataId())) {
     return;
   }
   for (MethodMetadataBuilder existingMethod : getDeclaredMethods()) {
     if (existingMethod.getMethodName().equals(replacement.getMethodName())) {
       if (AnnotatedJavaType.convertFromAnnotatedJavaTypes(existingMethod.getParameterTypes())
           .equals(
               AnnotatedJavaType.convertFromAnnotatedJavaTypes(
                   replacement.getParameterTypes()))) {
         for (Object key : customData.keySet()) {
           existingMethod.putCustomData(key, customData.get(key));
         }
         break;
       }
     }
   }
 }
  /**
   * @return the static utility entityManager() method used by other methods to obtain entity
   *     manager and available as a utility for user code (never returns nulls)
   */
  public MethodMetadata getEntityManagerMethod() {
    if (parent != null) {
      // The parent is required to guarantee this is available
      return parent.getEntityManagerMethod();
    }

    // Method definition to find or build
    final JavaSymbolName methodName = new JavaSymbolName(ENTITY_MANAGER_METHOD_NAME);
    final JavaType[] parameterTypes = {};
    final JavaType returnType = ENTITY_MANAGER;

    // Locate user-defined method
    final MethodMetadata userMethod = getGovernorMethod(methodName, parameterTypes);
    if (userMethod != null) {
      Assert.isTrue(
          userMethod.getReturnType().equals(returnType),
          "Method '"
              + methodName
              + "' on '"
              + destination
              + "' must return '"
              + returnType.getNameIncludingTypeParameters()
              + "'");
      return userMethod;
    }

    // Create method
    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

    if (Modifier.isAbstract(governorTypeDetails.getModifier())) {
      // Create an anonymous inner class that extends the abstract class (no-arg constructor is
      // available as this is a JPA entity)
      bodyBuilder.appendFormalLine(
          ENTITY_MANAGER.getNameIncludingTypeParameters(
                  false, builder.getImportRegistrationResolver())
              + " em = new "
              + destination.getSimpleTypeName()
              + "() {");
      // Handle any abstract methods in this class
      bodyBuilder.indent();
      for (final MethodMetadata method : governorTypeDetails.getMethods()) {
        if (Modifier.isAbstract(method.getModifier())) {
          final StringBuilder params = new StringBuilder();
          int i = -1;
          final List<AnnotatedJavaType> types = method.getParameterTypes();
          for (final JavaSymbolName name : method.getParameterNames()) {
            i++;
            if (i > 0) {
              params.append(", ");
            }
            final AnnotatedJavaType type = types.get(i);
            params.append(type.toString()).append(" ").append(name);
          }
          final int newModifier = method.getModifier() - Modifier.ABSTRACT;
          bodyBuilder.appendFormalLine(
              Modifier.toString(newModifier)
                  + " "
                  + method.getReturnType().getNameIncludingTypeParameters()
                  + " "
                  + method.getMethodName().getSymbolName()
                  + "("
                  + params.toString()
                  + ") {");
          bodyBuilder.indent();
          bodyBuilder.appendFormalLine("throw new UnsupportedOperationException();");
          bodyBuilder.indentRemove();
          bodyBuilder.appendFormalLine("}");
        }
      }
      bodyBuilder.indentRemove();
      bodyBuilder.appendFormalLine(
          "}." + getEntityManagerField().getFieldName().getSymbolName() + ";");
    } else {
      // Instantiate using the no-argument constructor (we know this is available as the entity must
      // comply with the JPA no-arg constructor requirement)
      bodyBuilder.appendFormalLine(
          ENTITY_MANAGER.getNameIncludingTypeParameters(
                  false, builder.getImportRegistrationResolver())
              + " em = new "
              + destination.getSimpleTypeName()
              + "()."
              + getEntityManagerField().getFieldName().getSymbolName()
              + ";");
    }

    bodyBuilder.appendFormalLine(
        "if (em == null) throw new IllegalStateException(\"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)\");");
    bodyBuilder.appendFormalLine("return em;");
    final int modifier = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            modifier,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
            new ArrayList<JavaSymbolName>(),
            bodyBuilder);
    return methodBuilder.build();
  }