private void addTransactionalAnnotation(
     final List<AnnotationMetadataBuilder> annotations, final boolean isPersistMethod) {
   final AnnotationMetadataBuilder transactionalBuilder =
       new AnnotationMetadataBuilder(TRANSACTIONAL);
   if (StringUtils.hasText(crudAnnotationValues.getTransactionManager())) {
     transactionalBuilder.addStringAttribute(
         "value", crudAnnotationValues.getTransactionManager());
   }
   if (isGaeEnabled && isPersistMethod) {
     transactionalBuilder.addEnumAttribute(
         "propagation", new EnumDetails(PROPAGATION, new JavaSymbolName("REQUIRES_NEW")));
   }
   annotations.add(transactionalBuilder);
 }
  /** @return a test for the persist method, if available and requested (may return null) */
  private MethodMetadataBuilder getRemoveMethodTest(
      final MemberTypeAdditions removeMethod,
      final MemberTypeAdditions findMethod,
      final MemberTypeAdditions flushMethod,
      final MethodMetadata identifierAccessorMethod) {
    if (!annotationValues.isRemove()
        || removeMethod == null
        || findMethod == null
        || identifierAccessorMethod == null) {
      // User does not want this method or one of its core dependencies
      return null;
    }

    // Prepare method signature
    JavaSymbolName methodName =
        new JavaSymbolName("test" + StringUtils.capitalize(removeMethod.getMethodName()));
    if (governorHasMethod(methodName)) {
      return null;
    }

    builder.getImportRegistrationResolver().addImport(identifierAccessorMethod.getReturnType());

    List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
    annotations.add(new AnnotationMetadataBuilder(TEST));
    if (isGaeSupported) {
      AnnotationMetadataBuilder transactionalBuilder = new AnnotationMetadataBuilder(TRANSACTIONAL);
      if (StringUtils.hasText(transactionManager)
          && !"transactionManager".equals(transactionManager)) {
        transactionalBuilder.addStringAttribute("value", transactionManager);
      }
      transactionalBuilder.addEnumAttribute(
          "propagation", new EnumDetails(PROPAGATION, new JavaSymbolName("SUPPORTS")));
      annotations.add(transactionalBuilder);
    }

    final String entityName = annotationValues.getEntity().getSimpleTypeName();

    InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
    bodyBuilder.appendFormalLine(
        entityName
            + " obj = dod."
            + dataOnDemandMetadata.getRandomPersistentEntityMethod().getMethodName().getSymbolName()
            + "();");
    bodyBuilder.appendFormalLine(
        "Assert.assertNotNull(\"Data on demand for '"
            + entityName
            + "' failed to initialize correctly\", obj);");
    bodyBuilder.appendFormalLine(
        identifierAccessorMethod.getReturnType().getSimpleTypeName()
            + " id = obj."
            + identifierAccessorMethod.getMethodName().getSymbolName()
            + "();");
    bodyBuilder.appendFormalLine(
        "Assert.assertNotNull(\"Data on demand for '"
            + entityName
            + "' failed to provide an identifier\", id);");
    bodyBuilder.appendFormalLine("obj = " + findMethod.getMethodCall() + ";");
    bodyBuilder.appendFormalLine(removeMethod.getMethodCall() + ";");

    if (flushMethod != null) {
      bodyBuilder.appendFormalLine(flushMethod.getMethodCall() + ";");
      flushMethod.copyAdditionsTo(builder, governorTypeDetails);
    }

    bodyBuilder.appendFormalLine(
        "Assert.assertNull(\"Failed to remove '"
            + entityName
            + "' with identifier '\" + id + \"'\", "
            + findMethod.getMethodCall()
            + ");");

    removeMethod.copyAdditionsTo(builder, governorTypeDetails);
    findMethod.copyAdditionsTo(builder, governorTypeDetails);

    MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(), Modifier.PUBLIC, methodName, JavaType.VOID_PRIMITIVE, bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder;
  }
  @Override
  public void createStringField(
      ClassOrInterfaceTypeDetails cid,
      JavaSymbolName fieldName,
      boolean notNull,
      boolean nullRequired,
      String decimalMin,
      String decimalMax,
      Integer sizeMin,
      Integer sizeMax,
      String regexp,
      String column,
      String comment,
      boolean unique,
      String value,
      boolean lob,
      boolean permitReservedWords,
      boolean transientModifier,
      List<AnnotationMetadataBuilder> extraAnnotations) {

    final String physicalTypeIdentifier = cid.getDeclaredByMetadataId();
    final StringField fieldDetails = new StringField(physicalTypeIdentifier, fieldName);
    fieldDetails.setNotNull(notNull);
    fieldDetails.setNullRequired(nullRequired);
    if (decimalMin != null) {
      fieldDetails.setDecimalMin(decimalMin);
    }
    if (decimalMax != null) {
      fieldDetails.setDecimalMax(decimalMax);
    }
    if (sizeMin != null) {
      fieldDetails.setSizeMin(sizeMin);
    }
    if (sizeMax != null) {
      fieldDetails.setSizeMax(sizeMax);
    }
    if (regexp != null) {
      fieldDetails.setRegexp(regexp.replace("\\", "\\\\"));
    }
    if (column != null) {
      fieldDetails.setColumn(column);
    }
    if (comment != null) {
      fieldDetails.setComment(comment);
    }
    if (unique) {
      fieldDetails.setUnique(true);
    }
    if (value != null) {
      fieldDetails.setValue(value);
    }

    if (lob) {
      fieldDetails
          .getInitedAnnotations()
          .add(new AnnotationMetadataBuilder("javax.persistence.Lob"));

      // ROO-3722: Add LAZY load in @Lob fields using @Basic
      AnnotationMetadataBuilder basicAnnotation =
          new AnnotationMetadataBuilder("javax.persistence.Basic");
      basicAnnotation.addEnumAttribute(
          "fetch",
          new EnumDetails(new JavaType("javax.persistence.FetchType"), new JavaSymbolName("LAZY")));
      fieldDetails.getInitedAnnotations().add(basicAnnotation);
    }

    if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
      fieldDetails.addAnnotations(extraAnnotations);
    }

    insertField(fieldDetails, permitReservedWords, false);
  }