private MethodMetadataBuilder getFinderFormMethod(final FinderMetadataDetails finder) {
    Validate.notNull(finder, "Method metadata required for finder");
    final JavaSymbolName finderFormMethodName =
        new JavaSymbolName(
            finder.getFinderMethodMetadata().getMethodName().getSymbolName() + "Form");

    final List<JavaType> methodParameterTypes = new ArrayList<JavaType>();
    final List<JavaSymbolName> methodParameterNames = new ArrayList<JavaSymbolName>();
    final List<JavaType> finderParameterTypes =
        AnnotatedJavaType.convertFromAnnotatedJavaTypes(
            finder.getFinderMethodMetadata().getParameterTypes());

    final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

    boolean needModel = false;
    for (final JavaType finderParameterType : finderParameterTypes) {
      JavaTypeMetadataDetails typeMd = specialDomainTypes.get(finderParameterType);
      JavaTypePersistenceMetadataDetails javaTypePersistenceMetadataHolder = null;
      if (finderParameterType.isCommonCollectionType()) {
        typeMd = specialDomainTypes.get(finderParameterType.getParameters().get(0));
        if (typeMd != null && typeMd.isApplicationType()) {
          javaTypePersistenceMetadataHolder = typeMd.getPersistenceDetails();
        }
      } else if (typeMd != null && typeMd.isEnumType()) {
        bodyBuilder.appendFormalLine(
            "uiModel.addAttribute(\""
                + typeMd.getPlural().toLowerCase()
                + "\", java.util.Arrays.asList("
                + getShortName(finderParameterType)
                + ".class.getEnumConstants()));");
      } else if (typeMd != null && typeMd.isApplicationType()) {
        javaTypePersistenceMetadataHolder = typeMd.getPersistenceDetails();
      }
      if (typeMd != null
          && javaTypePersistenceMetadataHolder != null
          && javaTypePersistenceMetadataHolder.getFindAllMethod() != null) {
        bodyBuilder.appendFormalLine(
            "uiModel.addAttribute(\""
                + typeMd.getPlural().toLowerCase()
                + "\", "
                + javaTypePersistenceMetadataHolder.getFindAllMethod().getMethodCall()
                + ");");
      }
      needModel = true;
    }
    if (finderParameterTypes.contains(DATE) || finderParameterTypes.contains(CALENDAR)) {
      bodyBuilder.appendFormalLine("addDateTimeFormatPatterns(uiModel);");
    }
    bodyBuilder.appendFormalLine(
        "return \""
            + controllerPath
            + "/"
            + finder.getFinderMethodMetadata().getMethodName().getSymbolName()
            + "\";");

    if (needModel) {
      methodParameterTypes.add(MODEL);
      methodParameterNames.add(new JavaSymbolName("uiModel"));
    }

    if (governorHasMethod(finderFormMethodName, methodParameterTypes)) {
      return null;
    }

    final List<AnnotationAttributeValue<?>> requestMappingAttributes =
        new ArrayList<AnnotationAttributeValue<?>>();
    final List<StringAttributeValue> arrayValues = new ArrayList<StringAttributeValue>();
    arrayValues.add(
        new StringAttributeValue(
            new JavaSymbolName("value"),
            "find="
                + finder
                    .getFinderMethodMetadata()
                    .getMethodName()
                    .getSymbolName()
                    .replaceFirst("find" + javaTypeMetadataHolder.getPlural(), "")));
    arrayValues.add(new StringAttributeValue(new JavaSymbolName("value"), "form"));
    requestMappingAttributes.add(
        new ArrayAttributeValue<StringAttributeValue>(new JavaSymbolName("params"), arrayValues));
    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);

    final MethodMetadataBuilder methodBuilder =
        new MethodMetadataBuilder(
            getId(),
            Modifier.PUBLIC,
            finderFormMethodName,
            JavaType.STRING,
            AnnotatedJavaType.convertFromJavaTypes(methodParameterTypes),
            methodParameterNames,
            bodyBuilder);
    methodBuilder.setAnnotations(annotations);
    return methodBuilder;
  }
  @Override
  protected ItdTypeDetailsProvidingMetadataItem getMetadata(
      final String metadataIdentificationString,
      final JavaType aspectName,
      final PhysicalTypeMetadata governorPhysicalTypeMetadata,
      final String itdFilename) {
    // We need to parse the annotation, which we expect to be present
    final WebJsonAnnotationValues annotationValues =
        new WebJsonAnnotationValues(governorPhysicalTypeMetadata);
    if (!annotationValues.isAnnotationFound()
        || annotationValues.getJsonObject() == null
        || governorPhysicalTypeMetadata.getMemberHoldingTypeDetails() == null) {
      return null;
    }

    // Lookup the form backing object's metadata
    final JavaType jsonObject = annotationValues.getJsonObject();
    final ClassOrInterfaceTypeDetails jsonTypeDetails =
        typeLocationService.getTypeDetails(jsonObject);
    if (jsonTypeDetails == null) {
      return null;
    }
    final LogicalPath jsonObjectPath =
        PhysicalTypeIdentifier.getPath(jsonTypeDetails.getDeclaredByMetadataId());
    final JsonMetadata jsonMetadata =
        (JsonMetadata)
            metadataService.get(JsonMetadata.createIdentifier(jsonObject, jsonObjectPath));
    if (jsonMetadata == null) {
      return null;
    }

    final PhysicalTypeMetadata backingObjectPhysicalTypeMetadata =
        (PhysicalTypeMetadata)
            metadataService.get(
                PhysicalTypeIdentifier.createIdentifier(
                    jsonObject, typeLocationService.getTypePath(jsonObject)));
    Validate.notNull(
        backingObjectPhysicalTypeMetadata,
        "Unable to obtain physical type metadata for type %s",
        jsonObject.getFullyQualifiedTypeName());
    final MemberDetails formBackingObjectMemberDetails =
        getMemberDetails(backingObjectPhysicalTypeMetadata);
    final MemberHoldingTypeDetails backingMemberHoldingTypeDetails =
        MemberFindingUtils.getMostConcreteMemberHoldingTypeDetailsWithTag(
            formBackingObjectMemberDetails, CustomDataKeys.PERSISTENT_TYPE);
    if (backingMemberHoldingTypeDetails == null) {
      return null;
    }

    // We need to be informed if our dependent metadata changes
    metadataDependencyRegistry.registerDependency(
        backingMemberHoldingTypeDetails.getDeclaredByMetadataId(), metadataIdentificationString);

    final Set<FinderMetadataDetails> finderDetails =
        webMetadataService.getDynamicFinderMethodsAndFields(
            jsonObject, formBackingObjectMemberDetails, metadataIdentificationString);
    if (finderDetails == null) {
      return null;
    }
    final Map<MethodMetadataCustomDataKey, MemberTypeAdditions> persistenceAdditions =
        webMetadataService.getCrudAdditions(jsonObject, metadataIdentificationString);
    final JavaTypePersistenceMetadataDetails javaTypePersistenceMetadataDetails =
        webMetadataService.getJavaTypePersistenceMetadataDetails(
            jsonObject, getMemberDetails(jsonObject), metadataIdentificationString);
    final PluralMetadata pluralMetadata =
        (PluralMetadata)
            metadataService.get(
                PluralMetadata.createIdentifier(
                    jsonObject, typeLocationService.getTypePath(jsonObject)));
    if (persistenceAdditions.isEmpty()
        || javaTypePersistenceMetadataDetails == null
        || pluralMetadata == null) {
      return null;
    }

    // Maintain a list of entities that are being tested
    managedEntityTypes.put(jsonObject, metadataIdentificationString);

    return new WebJsonMetadata(
        metadataIdentificationString,
        aspectName,
        governorPhysicalTypeMetadata,
        annotationValues,
        persistenceAdditions,
        javaTypePersistenceMetadataDetails.getIdentifierField(),
        pluralMetadata.getPlural(),
        finderDetails,
        jsonMetadata,
        introduceLayerComponents(governorPhysicalTypeMetadata));
  }