public List<JavaSymbolName> getFinders(
      MemberDetails memberDetails, String plural, int depth, Set<JavaSymbolName> exclusions) {
    Assert.notNull(memberDetails, "Member details required");
    Assert.hasText(plural, "Plural required");
    Assert.notNull(
        depth, "The depth of combinations used for finder signatures combinations required");
    Assert.notNull(exclusions, "Exclusions required");

    SortedSet<JavaSymbolName> finders = new TreeSet<JavaSymbolName>();

    List<FieldMetadata> fields = memberDetails.getFields();
    for (int i = 0; i < depth; i++) {
      SortedSet<JavaSymbolName> tempFinders = new TreeSet<JavaSymbolName>();
      for (FieldMetadata field : fields) {
        // Ignoring java.util.Map field types (see ROO-194)
        if (field == null || field.getFieldType().equals(new JavaType(Map.class.getName()))) {
          continue;
        }
        if (exclusions.contains(field.getFieldName())) {
          continue;
        }
        if (i == 0) {
          tempFinders.addAll(createFinders(field, finders, "find" + plural + "By", true));
        } else {
          tempFinders.addAll(createFinders(field, finders, "And", false));
          tempFinders.addAll(createFinders(field, finders, "Or", false));
        }
      }
      finders.addAll(tempFinders);
    }

    return Collections.unmodifiableList(new ArrayList<JavaSymbolName>(finders));
  }
  private Set<JavaSymbolName> populateFinders(
      Set<JavaSymbolName> finders,
      FieldMetadata field,
      String prepend,
      boolean isFirst,
      String keyWord) {
    Set<JavaSymbolName> tempFinders = new HashSet<JavaSymbolName>();

    if (isTransient(field)) {
      // No need to add transient fields
    } else if (isFirst) {
      String finderName =
          prepend + field.getFieldName().getSymbolNameCapitalisedFirstLetter() + keyWord;
      tempFinders.add(new JavaSymbolName(finderName));
    } else {
      for (JavaSymbolName finder : finders) {
        String finderName = finder.getSymbolName();
        if (!finderName.contains(field.getFieldName().getSymbolNameCapitalisedFirstLetter())) {
          tempFinders.add(
              new JavaSymbolName(
                  finderName
                      + prepend
                      + field.getFieldName().getSymbolNameCapitalisedFirstLetter()
                      + keyWord));
        }
      }
    }

    return tempFinders;
  }
  private MethodMetadata getFindByStringIdMethod() {
    if (!KEY.equals(identifierField.getFieldType())) {
      return null;
    }

    final String idFieldName = identifierField.getFieldName().getSymbolName();
    final JavaSymbolName methodName =
        new JavaSymbolName("find" + destination.getSimpleTypeName() + "ByStringId");
    final JavaType parameterType = STRING;
    final List<JavaSymbolName> parameterNames = Arrays.asList(new JavaSymbolName(idFieldName));
    final JavaType returnType = destination;

    // Check if a method with the same signature already exists in the target type
    final MethodMetadata method = getGovernorMethod(methodName, parameterType);
    if (method != null) {
      // If it already exists, just return the method and omit its generation via the ITD
      return method;
    }

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            PUBLIC_ABSTRACT,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterType),
            parameterNames,
            BODY);

    return methodBuilder.build();
  }
  private MethodMetadata getCountByParentMethod() {
    if (parentProperty == null) {
      return null;
    }

    JavaSymbolName methodName = new JavaSymbolName("count" + plural + "ByParentId");

    final JavaType idType =
        KEY.equals(identifierField.getFieldType()) ? STRING : identifierField.getFieldType();
    final JavaType[] parameterTypes = {idType};

    final MethodMetadata method = getGovernorMethod(methodName, parameterTypes);
    if (method != null) {
      return method;
    }

    final String idParamName =
        StringUtils.uncapitalize(parentProperty.getFieldType().getSimpleTypeName()) + "Id";
    final List<JavaSymbolName> parameterNames = Arrays.asList(new JavaSymbolName(idParamName));

    MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            PUBLIC_ABSTRACT,
            methodName,
            LONG_PRIMITIVE,
            AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
            parameterNames,
            BODY);

    return methodBuilder.build();
  }
 /**
  * Sets up the mock {@link RepositoryJpaLocator} and {@link PersistenceMemberLocator} to return a
  * mock repository for our test entity.
  */
 private void setUpMockRepository() {
   final ClassOrInterfaceTypeDetails mockRepositoryDetails =
       mock(ClassOrInterfaceTypeDetails.class);
   final FieldMetadata mockFieldMetadata = mock(FieldMetadata.class);
   final JavaType mockRepositoryType = mock(JavaType.class);
   when(mockRepositoryType.getSimpleTypeName()).thenReturn("ClinicRepo");
   when(mockIdType.getFullyQualifiedTypeName()).thenReturn(Long.class.getName());
   when(mockRepositoryDetails.getName()).thenReturn(mockRepositoryType);
   when(mockFieldMetadata.getFieldType()).thenReturn(mockIdType);
   when(mockRepositoryLocator.getRepositories(mockTargetEntity))
       .thenReturn(Arrays.asList(mockRepositoryDetails));
 }
 private void doModification(final FieldMetadata field, final CustomData customData) {
   MemberHoldingTypeDetails memberHoldingTypeDetails =
       memberHoldingTypeDetailsMap.get(field.getDeclaredByMetadataId());
   if (memberHoldingTypeDetails != null) {
     FieldMetadata matchedField = memberHoldingTypeDetails.getField(field.getFieldName());
     if (matchedField != null
         && !matchedField.getCustomData().keySet().containsAll(customData.keySet())) {
       TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails);
       typeDetailsBuilder.addDataToField(field, customData);
       changed = true;
     }
   }
 }
 public void addDataToField(final FieldMetadata 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 (FieldMetadataBuilder existingField : getDeclaredFields()) {
     if (existingField.getFieldName().equals(replacement.getFieldName())) {
       for (Object key : customData.keySet()) {
         existingField.putCustomData(key, customData.get(key));
       }
       break;
     }
   }
 }
  public void addField(final FieldMetadata field) {
    Assert.notNull(field, "Field metadata not provided");

    // Obtain the physical type and ITD mutable details
    PhysicalTypeMetadata ptm =
        (PhysicalTypeMetadata) metadataService.get(field.getDeclaredByMetadataId());
    Assert.notNull(
        ptm,
        "Java source code unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
    PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
    Assert.notNull(
        ptd,
        "Java source code details unavailable for type "
            + PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
    ClassOrInterfaceTypeDetailsBuilder cidBuilder =
        new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) ptd);

    // Automatically add JSR 303 (Bean Validation API) support if there is
    // no current JSR 303 support but a JSR 303 annotation is present
    boolean jsr303Required = false;
    for (AnnotationMetadata annotation : field.getAnnotations()) {
      if (annotation
          .getAnnotationType()
          .getFullyQualifiedTypeName()
          .startsWith("javax.validation")) {
        jsr303Required = true;
        break;
      }
    }

    LogicalPath path = PhysicalTypeIdentifier.getPath(cidBuilder.getDeclaredByMetadataId());

    if (jsr303Required) {
      // It's more likely the version below represents a later version
      // than any specified in the user's own dependency list
      projectOperations.addDependency(
          path.getModule(), "javax.validation", "validation-api", "1.0.0.GA");
    }
    cidBuilder.addField(field);
    createOrUpdateTypeOnDisk(cidBuilder.build());
  }
  private MethodMetadata getFindEntriesByParentMethod() {
    if (parentProperty == null) {
      return null;
    }

    JavaSymbolName methodName =
        new JavaSymbolName("find" + domainType.getSimpleTypeName() + "EntriesByParentId");

    final JavaType idType =
        KEY.equals(identifierField.getFieldType()) ? STRING : identifierField.getFieldType();
    final JavaType[] parameterTypes = {idType, INT_PRIMITIVE, INT_PRIMITIVE};

    final MethodMetadata method = getGovernorMethod(methodName, parameterTypes);
    if (method != null) {
      return method;
    }

    final String idParamName =
        StringUtils.uncapitalize(parentProperty.getFieldType().getSimpleTypeName()) + "Id";
    final List<JavaSymbolName> parameterNames =
        Arrays.asList(
            new JavaSymbolName(idParamName),
            new JavaSymbolName("firstResult"),
            new JavaSymbolName("maxResults"));
    final JavaType returnType =
        new JavaType(
            LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(domainType));

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            PUBLIC_ABSTRACT,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
            parameterNames,
            BODY);

    return methodBuilder.build();
  }
  /**
   * Locates the entity manager field that should be used.
   *
   * <p>If a parent is defined, it must provide the field.
   *
   * <p>We generally expect the field to be named "entityManager" and be of type
   * javax.persistence.EntityManager. We also require it to be public or protected, and annotated
   * with @PersistenceContext. If there is an existing field which doesn't meet these latter
   * requirements, we add an underscore prefix to the "entityManager" name and try again, until such
   * time as we come up with a unique name that either meets the requirements or the name is not
   * used and we will create it.
   *
   * @return the entity manager field (never returns null)
   */
  public FieldMetadata getEntityManagerField() {
    if (parent != null) {
      // The parent is required to guarantee this is available
      return parent.getEntityManagerField();
    }

    // Need to locate it ourself
    int index = -1;
    while (true) {
      // Compute the required field name
      index++;
      final JavaSymbolName fieldSymbolName =
          new JavaSymbolName(StringUtils.repeat("_", index) + "entityManager");
      final FieldMetadata candidate = governorTypeDetails.getField(fieldSymbolName);
      if (candidate != null) {
        // Verify if candidate is suitable

        if (!Modifier.isPublic(candidate.getModifier())
            && !Modifier.isProtected(candidate.getModifier())
            && (Modifier.TRANSIENT != candidate.getModifier())) {
          // Candidate is not public and not protected and not simply a transient field (in which
          // case subclasses
          // will see the inherited field), so any subsequent subclasses won't be able to see it.
          // Give up!
          continue;
        }

        if (!candidate.getFieldType().equals(ENTITY_MANAGER)) {
          // Candidate isn't an EntityManager, so give up
          continue;
        }

        if (MemberFindingUtils.getAnnotationOfType(candidate.getAnnotations(), PERSISTENCE_CONTEXT)
            == null) {
          // Candidate doesn't have a PersistenceContext annotation, so give up
          continue;
        }

        // If we got this far, we found a valid candidate
        return candidate;
      }

      // Candidate not found, so let's create one
      final List<AnnotationMetadataBuilder> annotations =
          new ArrayList<AnnotationMetadataBuilder>();
      final AnnotationMetadataBuilder annotationBuilder =
          new AnnotationMetadataBuilder(PERSISTENCE_CONTEXT);
      if (StringUtils.hasText(crudAnnotationValues.getPersistenceUnit())) {
        annotationBuilder.addStringAttribute("unitName", crudAnnotationValues.getPersistenceUnit());
      }
      annotations.add(annotationBuilder);

      final FieldMetadataBuilder fieldBuilder =
          new FieldMetadataBuilder(
              getId(), Modifier.TRANSIENT, annotations, fieldSymbolName, ENTITY_MANAGER);
      return fieldBuilder.build();
    }
  }
  private Set<JavaSymbolName> createFinders(
      FieldMetadata field, Set<JavaSymbolName> finders, String prepend, boolean isFirst) {
    Set<JavaSymbolName> tempFinders = new HashSet<JavaSymbolName>();

    if (isNumberOrDate(field.getFieldType())) {
      for (ReservedToken keyWord : ReservedTokenHolder.NUMERIC_TOKENS) {
        tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
      }
    } else if (field.getFieldType().equals(JavaType.STRING)) {
      for (ReservedToken keyWord : ReservedTokenHolder.STRING_TOKENS) {
        tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
      }
    } else if (field.getFieldType().equals(JavaType.BOOLEAN_OBJECT)
        || field.getFieldType().equals(JavaType.BOOLEAN_PRIMITIVE)) {
      for (ReservedToken keyWord : ReservedTokenHolder.BOOLEAN_TOKENS) {
        tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
      }
    } else {
      tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, ""));
    }

    return tempFinders;
  }
  public Set<JavaType> getPersistentFieldTypes(
      final JavaType thisType, final PersistenceMemberLocator persistenceMemberLocator) {
    final MethodMetadata identifierAccessor =
        persistenceMemberLocator.getIdentifierAccessor(thisType);
    final MethodMetadata versionAccessor = persistenceMemberLocator.getVersionAccessor(thisType);

    final Set<JavaType> fieldTypes = new LinkedHashSet<JavaType>();
    for (final MethodMetadata method : getMethods()) {
      // Not interested in non-accessor methods or persistence identifiers
      // and version fields
      if (!BeanInfoUtils.isAccessorMethod(method)
          || method.hasSameName(identifierAccessor, versionAccessor)) {
        continue;
      }

      // Not interested in fields that are JPA transient fields or
      // immutable fields
      final FieldMetadata field = BeanInfoUtils.getFieldForJavaBeanMethod(this, method);
      if (field == null
          || field.getCustomData().keySet().contains(CustomDataKeys.TRANSIENT_FIELD)
          || !BeanInfoUtils.hasAccessorAndMutator(field, this)) {
        continue;
      }
      final JavaType returnType = method.getReturnType();
      if (returnType.isCommonCollectionType()) {
        for (final JavaType genericType : returnType.getParameters()) {
          fieldTypes.add(genericType);
        }
      } else {
        if (!field.getCustomData().keySet().contains(EMBEDDED_FIELD)) {
          fieldTypes.add(returnType);
        }
      }
    }
    return fieldTypes;
  }
  private MethodMetadataBuilder getFinderMethod(final FinderMetadataDetails finderMetadataDetails) {
    Validate.notNull(finderMetadataDetails, "Method metadata required for finder");
    final JavaSymbolName finderMethodName =
        new JavaSymbolName(
            finderMetadataDetails.getFinderMethodMetadata().getMethodName().getSymbolName());

    final List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
    final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();

    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
    final StringBuilder methodParams = new StringBuilder();

    boolean dateFieldPresent = !dateTypes.isEmpty();
    for (final FieldMetadata field : finderMetadataDetails.getFinderMethodParamFields()) {
      final JavaSymbolName fieldName = field.getFieldName();
      final List<AnnotationMetadata> annotations = new ArrayList<AnnotationMetadata>();
      final List<AnnotationAttributeValue<?>> attributes =
          new ArrayList<AnnotationAttributeValue<?>>();
      attributes.add(
          new StringAttributeValue(
              new JavaSymbolName("value"), uncapitalize(fieldName.getSymbolName())));
      if (field.getFieldType().equals(JavaType.BOOLEAN_PRIMITIVE)
          || field.getFieldType().equals(JavaType.BOOLEAN_OBJECT)) {
        attributes.add(new BooleanAttributeValue(new JavaSymbolName("required"), false));
      }
      final AnnotationMetadataBuilder requestParamAnnotation =
          new AnnotationMetadataBuilder(REQUEST_PARAM, attributes);
      annotations.add(requestParamAnnotation.build());
      if (field.getFieldType().equals(DATE) || field.getFieldType().equals(CALENDAR)) {
        dateFieldPresent = true;
        final AnnotationMetadata annotation =
            MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), DATE_TIME_FORMAT);
        if (annotation != null) {
          getShortName(DATE_TIME_FORMAT);
          annotations.add(annotation);
        }
      }
      parameterNames.add(fieldName);
      parameterTypes.add(new AnnotatedJavaType(field.getFieldType(), annotations));

      if (field.getFieldType().equals(JavaType.BOOLEAN_OBJECT)) {
        methodParams.append(fieldName + " == null ? Boolean.FALSE : " + fieldName + ", ");
      } else {
        methodParams.append(fieldName + ", ");
      }
    }

    if (methodParams.length() > 0) {
      methodParams.delete(methodParams.length() - 2, methodParams.length());
    }

    final List<AnnotationAttributeValue<?>> firstResultAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    firstResultAttributes.add(new StringAttributeValue(new JavaSymbolName("value"), "page"));
    firstResultAttributes.add(new BooleanAttributeValue(new JavaSymbolName("required"), false));
    final AnnotationMetadataBuilder firstResultAnnotation =
        new AnnotationMetadataBuilder(REQUEST_PARAM, firstResultAttributes);

    final List<AnnotationAttributeValue<?>> maxResultsAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    maxResultsAttributes.add(new StringAttributeValue(new JavaSymbolName("value"), "size"));
    maxResultsAttributes.add(new BooleanAttributeValue(new JavaSymbolName("required"), false));
    final AnnotationMetadataBuilder maxResultAnnotation =
        new AnnotationMetadataBuilder(REQUEST_PARAM, maxResultsAttributes);

    final List<AnnotationAttributeValue<?>> sortFieldNameAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    sortFieldNameAttributes.add(
        new StringAttributeValue(new JavaSymbolName("value"), "sortFieldName"));
    sortFieldNameAttributes.add(new BooleanAttributeValue(new JavaSymbolName("required"), false));
    final AnnotationMetadataBuilder sortFieldNameAnnotation =
        new AnnotationMetadataBuilder(REQUEST_PARAM, sortFieldNameAttributes);

    final List<AnnotationAttributeValue<?>> sortOrderAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    sortOrderAttributes.add(new StringAttributeValue(new JavaSymbolName("value"), "sortOrder"));
    sortOrderAttributes.add(new BooleanAttributeValue(new JavaSymbolName("required"), false));
    final AnnotationMetadataBuilder sortOrderAnnotation =
        new AnnotationMetadataBuilder(REQUEST_PARAM, sortOrderAttributes);

    parameterTypes.add(
        new AnnotatedJavaType(
            new JavaType(Integer.class.getName()), firstResultAnnotation.build()));
    parameterTypes.add(
        new AnnotatedJavaType(new JavaType(Integer.class.getName()), maxResultAnnotation.build()));
    parameterTypes.add(
        new AnnotatedJavaType(
            new JavaType(String.class.getName()), sortFieldNameAnnotation.build()));
    parameterTypes.add(
        new AnnotatedJavaType(new JavaType(String.class.getName()), sortOrderAnnotation.build()));

    parameterTypes.add(new AnnotatedJavaType(MODEL));
    if (getGovernorMethod(
            finderMethodName, AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes))
        != null) {
      return null;
    }

    final List<JavaSymbolName> newParamNames = new ArrayList<JavaSymbolName>();
    newParamNames.addAll(parameterNames);
    newParamNames.add(new JavaSymbolName("page"));
    newParamNames.add(new JavaSymbolName("size"));
    newParamNames.add(new JavaSymbolName("sortFieldName"));
    newParamNames.add(new JavaSymbolName("sortOrder"));
    newParamNames.add(new JavaSymbolName("uiModel"));

    final List<AnnotationAttributeValue<?>> requestMappingAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    requestMappingAttributes.add(
        new StringAttributeValue(
            new JavaSymbolName("params"),
            "find="
                + finderMetadataDetails
                    .getFinderMethodMetadata()
                    .getMethodName()
                    .getSymbolName()
                    .replaceFirst("find" + javaTypeMetadataHolder.getPlural(), "")));
    requestMappingAttributes.add(
        new EnumAttributeValue(
            new JavaSymbolName("method"),
            new EnumDetails(REQUEST_METHOD, new JavaSymbolName("GET"))));
    final AnnotationMetadataBuilder requestMapping =
        new AnnotationMetadataBuilder(REQUEST_MAPPING, requestMappingAttributes);
    final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
    annotations.add(requestMapping);

    bodyBuilder.appendFormalLine("if (page != null || size != null) {");
    bodyBuilder.indent();
    bodyBuilder.appendFormalLine("int sizeNo = size == null ? 10 : size.intValue();");
    bodyBuilder.appendFormalLine(
        "final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;");
    String methodParamsString = methodParams.toString();
    if (StringUtils.isNotBlank(methodParamsString)) {
      methodParamsString.concat(", ");
    }
    bodyBuilder.appendFormalLine(
        "uiModel.addAttribute(\""
            + javaTypeMetadataHolder.getPlural().toLowerCase()
            + "\", "
            + getShortName(formBackingType)
            + "."
            + finderMetadataDetails.getFinderMethodMetadata().getMethodName().getSymbolName()
            + "("
            + methodParamsString
            + "sortFieldName, sortOrder).setFirstResult(firstResult).setMaxResults(sizeNo).getResultList());");

    char[] methodNameArray =
        finderMetadataDetails
            .getFinderMethodMetadata()
            .getMethodName()
            .getSymbolName()
            .toCharArray();
    methodNameArray[0] = Character.toUpperCase(methodNameArray[0]);
    String countMethodName = "count" + new String(methodNameArray);

    bodyBuilder.appendFormalLine(
        "float nrOfPages = (float) "
            + getShortName(formBackingType)
            + "."
            + countMethodName
            + "("
            + methodParamsString
            + ") / sizeNo;");
    bodyBuilder.appendFormalLine(
        "uiModel.addAttribute(\"maxPages\", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));");
    bodyBuilder.indentRemove();
    bodyBuilder.appendFormalLine("} else {");
    bodyBuilder.indent();
    bodyBuilder.appendFormalLine(
        "uiModel.addAttribute(\""
            + javaTypeMetadataHolder.getPlural().toLowerCase()
            + "\", "
            + getShortName(formBackingType)
            + "."
            + finderMetadataDetails.getFinderMethodMetadata().getMethodName().getSymbolName()
            + "("
            + methodParamsString
            + "sortFieldName, sortOrder).getResultList());");
    bodyBuilder.indentRemove();
    bodyBuilder.appendFormalLine("}");

    if (dateFieldPresent) {
      bodyBuilder.appendFormalLine("addDateTimeFormatPatterns(uiModel);");
    }
    bodyBuilder.appendFormalLine("return \"" + controllerPath + "/list\";");

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            Modifier.PUBLIC,
            finderMethodName,
            JavaType.STRING,
            parameterTypes,
            newParamNames,
            bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder;
  }
  private void addOptionalIntegrationTestClassIntroductions() {
    // Add the GAE test helper field if the user did not define it on the
    // governor directly
    final JavaType helperType = GAE_LOCAL_SERVICE_TEST_HELPER;
    FieldMetadata helperField = governorTypeDetails.getField(new JavaSymbolName("helper"));
    if (helperField != null) {
      Assert.isTrue(
          helperField
              .getFieldType()
              .getFullyQualifiedTypeName()
              .equals(helperType.getFullyQualifiedTypeName()),
          "Field 'helper' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be of type '"
              + helperType.getFullyQualifiedTypeName()
              + "'");
    } else {
      // Add the field via the ITD
      String initializer =
          "new LocalServiceTestHelper(new com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig())";
      FieldMetadataBuilder fieldBuilder =
          new FieldMetadataBuilder(
              getId(),
              Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
              new JavaSymbolName("helper"),
              helperType,
              initializer);
      builder.addField(fieldBuilder);
    }

    // Prepare setUp method signature
    JavaSymbolName setUpMethodName = new JavaSymbolName("setUp");
    MethodMetadata setUpMethod = getGovernorMethod(setUpMethodName, SETUP_PARAMETERS);
    if (setUpMethod != null) {
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(setUpMethod.getAnnotations(), BEFORE_CLASS),
          "Method 'setUp' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @BeforeClass");
    } else {
      // Add the method via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(BEFORE_CLASS));

      InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
      bodyBuilder.appendFormalLine("helper.setUp();");

      MethodMetadataBuilder methodBuilder =
          new MethodMetadataBuilder(
              getId(),
              Modifier.PUBLIC | Modifier.STATIC,
              setUpMethodName,
              JavaType.VOID_PRIMITIVE,
              AnnotatedJavaType.convertFromJavaTypes(SETUP_PARAMETERS),
              new ArrayList<JavaSymbolName>(),
              bodyBuilder);
      methodBuilder.setAnnotations(annotations);
      builder.addMethod(methodBuilder);
    }

    // Prepare tearDown method signature
    JavaSymbolName tearDownMethodName = new JavaSymbolName("tearDown");
    MethodMetadata tearDownMethod = getGovernorMethod(tearDownMethodName, TEARDOWN_PARAMETERS);
    if (tearDownMethod != null) {
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(tearDownMethod.getAnnotations(), AFTER_CLASS),
          "Method 'tearDown' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @AfterClass");
    } else {
      // Add the method via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(AFTER_CLASS));

      InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
      bodyBuilder.appendFormalLine("helper.tearDown();");

      MethodMetadataBuilder methodBuilder =
          new MethodMetadataBuilder(
              getId(),
              Modifier.PUBLIC | Modifier.STATIC,
              tearDownMethodName,
              JavaType.VOID_PRIMITIVE,
              AnnotatedJavaType.convertFromJavaTypes(TEARDOWN_PARAMETERS),
              new ArrayList<JavaSymbolName>(),
              bodyBuilder);
      methodBuilder.setAnnotations(annotations);
      builder.addMethod(methodBuilder);
    }
  }
  /** Adds the JUnit and Spring type level annotations if needed */
  private void addRequiredIntegrationTestClassIntroductions(final JavaType dodGovernor) {
    // Add an @RunWith(SpringJunit4ClassRunner) annotation to the type, if
    // the user did not define it on the governor directly
    if (MemberFindingUtils.getAnnotationOfType(governorTypeDetails.getAnnotations(), RUN_WITH)
        == null) {
      AnnotationMetadataBuilder runWithBuilder = new AnnotationMetadataBuilder(RUN_WITH);
      runWithBuilder.addClassAttribute(
          "value", "org.springframework.test.context.junit4.SpringJUnit4ClassRunner");
      builder.addAnnotation(runWithBuilder);
    }

    // Add an @ContextConfiguration("classpath:/applicationContext.xml")
    // annotation to the type, if the user did not define it on the governor
    // directly
    if (MemberFindingUtils.getAnnotationOfType(
            governorTypeDetails.getAnnotations(), CONTEXT_CONFIGURATION)
        == null) {
      AnnotationMetadataBuilder contextConfigurationBuilder =
          new AnnotationMetadataBuilder(CONTEXT_CONFIGURATION);
      contextConfigurationBuilder.addStringAttribute(
          "locations", "classpath:/META-INF/spring/applicationContext*.xml");
      builder.addAnnotation(contextConfigurationBuilder);
    }

    // Add an @Transactional, if the user did not define it on the governor
    // directly
    if (annotationValues.isTransactional()
        && MemberFindingUtils.getAnnotationOfType(
                governorTypeDetails.getAnnotations(), TRANSACTIONAL)
            == null) {
      AnnotationMetadataBuilder transactionalBuilder = new AnnotationMetadataBuilder(TRANSACTIONAL);
      if (StringUtils.hasText(transactionManager)
          && !"transactionManager".equals(transactionManager)) {
        transactionalBuilder.addStringAttribute("value", transactionManager);
      }
      builder.addAnnotation(transactionalBuilder);
    }

    // Add the data on demand field if the user did not define it on the
    // governor directly
    FieldMetadata field = governorTypeDetails.getField(new JavaSymbolName("dod"));
    if (field != null) {
      Assert.isTrue(
          field.getFieldType().equals(dodGovernor),
          "Field 'dod' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be of type '"
              + dodGovernor.getFullyQualifiedTypeName()
              + "'");
      Assert.notNull(
          MemberFindingUtils.getAnnotationOfType(field.getAnnotations(), AUTOWIRED),
          "Field 'dod' on '"
              + destination.getFullyQualifiedTypeName()
              + "' must be annotated with @Autowired");
    } else {
      // Add the field via the ITD
      List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
      annotations.add(new AnnotationMetadataBuilder(AUTOWIRED));
      FieldMetadataBuilder fieldBuilder =
          new FieldMetadataBuilder(
              getId(), Modifier.PRIVATE, annotations, new JavaSymbolName("dod"), dodGovernor);
      builder.addField(fieldBuilder);
    }

    builder.getImportRegistrationResolver().addImport(ASSERT);
  }
  /** @return the find (by ID) method (may return null) */
  public MethodMetadata getFindMethod() {
    if ("".equals(crudAnnotationValues.getFindMethod())) {
      return null;
    }

    // Method definition to find or build
    final String idFieldName = identifierField.getFieldName().getSymbolName();
    final JavaSymbolName methodName =
        new JavaSymbolName(crudAnnotationValues.getFindMethod() + destination.getSimpleTypeName());
    final JavaType parameterType = identifierField.getFieldType();
    final List<JavaSymbolName> parameterNames = Arrays.asList(new JavaSymbolName(idFieldName));
    final JavaType returnType = destination;

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

    // Create method
    final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
    if (isGaeEnabled) {
      addTransactionalAnnotation(annotations);
    }

    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

    if (JavaType.STRING.equals(identifierField.getFieldType())) {
      bodyBuilder.appendFormalLine(
          "if (" + idFieldName + " == null || " + idFieldName + ".length() == 0) return null;");
    } else if (!identifierField.getFieldType().isPrimitive()) {
      bodyBuilder.appendFormalLine("if (" + idFieldName + " == null) return null;");
    }

    bodyBuilder.appendFormalLine(
        "return "
            + ENTITY_MANAGER_METHOD_NAME
            + "().find("
            + returnType.getSimpleTypeName()
            + ".class, "
            + idFieldName
            + ");");

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            Modifier.PUBLIC | Modifier.STATIC,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterType),
            parameterNames,
            bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder.build();
  }
  private MethodMetadata getDelegateMethod(
      final JavaSymbolName methodName, final String methodDelegateName) {
    // Method definition to find or build
    final JavaType[] parameterTypes = {};

    // Locate user-defined method
    final MethodMetadata userMethod = getGovernorMethod(methodName, parameterTypes);
    if (userMethod != null) {
      return userMethod;
    }

    // Create the method
    final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();

    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

    // Address non-injected entity manager field
    final MethodMetadata entityManagerMethod = getEntityManagerMethod();
    Assert.notNull(entityManagerMethod, "Entity manager method should not have returned null");

    // Use the getEntityManager() method to acquire an entity manager (the method will throw an
    // exception if it cannot be acquired)
    final String entityManagerFieldName = getEntityManagerField().getFieldName().getSymbolName();
    bodyBuilder.appendFormalLine(
        "if (this."
            + entityManagerFieldName
            + " == null) this."
            + entityManagerFieldName
            + " = "
            + entityManagerMethod.getMethodName().getSymbolName()
            + "();");

    JavaType returnType = JavaType.VOID_PRIMITIVE;
    if ("flush".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".flush();");
    } else if ("clear".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".clear();");
    } else if ("merge".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      returnType = new JavaType(destination.getSimpleTypeName());
      bodyBuilder.appendFormalLine(
          destination.getSimpleTypeName()
              + " merged = this."
              + entityManagerFieldName
              + ".merge(this);");
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".flush();");
      bodyBuilder.appendFormalLine("return merged;");
    } else if ("remove".equals(methodDelegateName)) {
      addTransactionalAnnotation(annotations);
      bodyBuilder.appendFormalLine("if (this." + entityManagerFieldName + ".contains(this)) {");
      bodyBuilder.indent();
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".remove(this);");
      bodyBuilder.indentRemove();
      bodyBuilder.appendFormalLine("} else {");
      bodyBuilder.indent();
      bodyBuilder.appendFormalLine(
          destination.getSimpleTypeName()
              + " attached = "
              + destination.getSimpleTypeName()
              + "."
              + getFindMethod().getMethodName().getSymbolName()
              + "(this."
              + identifierField.getFieldName().getSymbolName()
              + ");");
      bodyBuilder.appendFormalLine("this." + entityManagerFieldName + ".remove(attached);");
      bodyBuilder.indentRemove();
      bodyBuilder.appendFormalLine("}");
    } else {
      // Persist
      addTransactionalAnnotation(annotations, true);
      bodyBuilder.appendFormalLine(
          "this." + entityManagerFieldName + "." + methodDelegateName + "(this);");
    }

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            Modifier.PUBLIC,
            methodName,
            returnType,
            AnnotatedJavaType.convertFromJavaTypes(parameterTypes),
            new ArrayList<JavaSymbolName>(),
            bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder.build();
  }
Example #18
0
  /**
   * Method to obtain details of some entity
   *
   * @param out
   */
  private void getEntityDetails(String entityName, PrintWriter out)
      throws ServletException, IOException {

    List<Entity> allEntities = new ArrayList<Entity>();

    // Getting all entities
    Set<ClassOrInterfaceTypeDetails> entities =
        getTypeLocationService()
            .findClassesOrInterfaceDetailsWithAnnotation(new JavaType(RooJavaBean.class));

    Iterator<ClassOrInterfaceTypeDetails> it = entities.iterator();

    while (it.hasNext()) {
      // Getting entity
      ClassOrInterfaceTypeDetails entity = it.next();

      // Entity Name
      String currentEntityName = entity.getName().getFullyQualifiedTypeName();
      String topLevelPackage = getProjectOperations().getFocusedTopLevelPackage().toString();

      // Replacing topLevelPackage with ~
      currentEntityName = currentEntityName.replace(topLevelPackage, "~");

      // Getting info only about selected entity
      if (entityName.equals(currentEntityName)) {
        List<Field> entityFields = new ArrayList<Field>();
        for (FieldMetadata field : entity.getDeclaredFields()) {

          // Getting fields values
          String fieldName = field.getFieldName().getSymbolName();
          String fieldType = field.getFieldType().getSimpleTypeName();

          // Getting referenced class
          String referencedClass = "";
          if (field.getFieldType().getSimpleTypeName().equals("Set")
              || field.getFieldType().getSimpleTypeName().equals("List")) {
            referencedClass = field.getFieldType().getParameters().get(0).getSimpleTypeName();
          } else {
            AnnotationMetadata manyToOneAnnotation =
                field.getAnnotation(new JavaType("javax.persistence.ManyToOne"));
            if (manyToOneAnnotation != null) {
              referencedClass = field.getFieldType().getFullyQualifiedTypeName();
              referencedClass = referencedClass.replace(topLevelPackage, "~");
              fieldType = "Reference";
            }
          }

          // Creating entityField Object
          Field entityField = new Field(fieldName, fieldType, referencedClass);
          // Adding field to entity
          entityFields.add(entityField);
        }

        // Checking if current entity is abstract
        boolean isAbstractEntity = entity.isAbstract();

        // Adding extends type
        List<String> extendsTypes = new ArrayList<String>();
        for (JavaType extendsType : entity.getExtendsTypes()) {
          extendsTypes.add(extendsType.getFullyQualifiedTypeName().replace(topLevelPackage, "~"));
        }

        // Creating Entity Object
        allEntities.add(
            new Entity(currentEntityName, extendsTypes, isAbstractEntity, entityFields));
      }
    }

    // Returning JSON
    ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
    String json = ow.writeValueAsString(allEntities);
    out.println(json);
  }
 private boolean isTransient(FieldMetadata field) {
   return Modifier.isTransient(field.getModifier())
       || field.getCustomData().keySet().contains(PersistenceCustomDataKeys.TRANSIENT_FIELD);
 }