/*
   * (non-Javadoc)
   * @see org.springframework.data.rest.core.mapping.ResourceMappings#getSearchResourceMappings(java.lang.Class)
   */
  @Override
  public SearchResourceMappings getSearchResourceMappings(Class<?> domainType) {

    Assert.notNull(domainType, "Type must not be null!");

    if (searchCache.containsKey(domainType)) {
      return searchCache.get(domainType);
    }

    RepositoryInformation repositoryInformation =
        repositories.getRepositoryInformationFor(domainType);
    List<MethodResourceMapping> mappings = new ArrayList<MethodResourceMapping>();
    ResourceMetadata resourceMapping = getMetadataFor(domainType);

    if (resourceMapping.isExported()) {
      for (Method queryMethod : repositoryInformation.getQueryMethods()) {
        RepositoryMethodResourceMapping methodMapping =
            new RepositoryMethodResourceMapping(
                queryMethod, resourceMapping, repositoryInformation);
        if (methodMapping.isExported()) {
          mappings.add(methodMapping);
        }
      }
    }

    SearchResourceMappings searchResourceMappings = new SearchResourceMappings(mappings);
    searchCache.put(domainType, searchResourceMappings);
    return searchResourceMappings;
  }
 protected void populateJpaClasses() {
   if (repositoryInformations == null) {
     repositoryInformations = new ArrayList<RepositoryInformation>();
   }
   for (Class<?> clazz : repositories) {
     RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(clazz);
     if (includeClasses != null) {
       if (includeClasses.contains(repoInfo.getDomainType())) {
         repositoryInformations.add(repoInfo);
       }
     } else if (excludeClasses != null) {
       if (!excludeClasses.contains(repoInfo.getDomainType())) {
         repositoryInformations.add(repoInfo);
       }
     } else {
       repositoryInformations.add(repoInfo);
     }
   }
 }
  private final void populateCache(
      Repositories repositories, RelProvider provider, RepositoryDetectionStrategy strategy) {

    for (Class<?> type : repositories) {

      RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(type);
      Class<?> repositoryInterface = repositoryInformation.getRepositoryInterface();
      PersistentEntity<?, ?> entity = repositories.getPersistentEntity(type);

      CollectionResourceMapping mapping =
          new RepositoryCollectionResourceMapping(repositoryInformation, provider, strategy);
      RepositoryAwareResourceMetadata information =
          new RepositoryAwareResourceMetadata(entity, mapping, this, repositoryInformation);

      addToCache(repositoryInterface, information);

      if (!hasMetadataFor(type) || information.isPrimary()) {
        addToCache(type, information);
      }
    }
  }
  private final void populateCache(Repositories repositories) {

    for (Class<?> type : repositories) {

      RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(type);
      Class<?> repositoryInterface = repositoryInformation.getRepositoryInterface();

      CollectionResourceMapping mapping =
          new RepositoryCollectionResourceMapping(repositoryInterface, relProvider);

      RepositoryAwareResourceInformation information =
          new RepositoryAwareResourceInformation(
              repositories, mapping, this, repositoryInformation);

      cache.put(repositoryInterface, information);

      if (!cache.containsKey(type) || information.isPrimary()) {
        cache.put(type, information);
      }
    }
  }
  /**
   * Creates the {@link Descriptor}s for pagination parameters.
   *
   * @param type
   * @return
   */
  private List<Descriptor> getPaginationDescriptors(Class<?> type, HttpMethod method) {

    RepositoryInformation information = repositories.getRepositoryInformationFor(type);

    if (!information.isPagingRepository() || !getType(method).equals(Type.SAFE)) {
      return Collections.emptyList();
    }

    Link linkToCollectionResource = entityLinks.linkToCollectionResource(type);
    List<TemplateVariable> variables = linkToCollectionResource.getVariables();
    List<Descriptor> descriptors = new ArrayList<Descriptor>(variables.size());

    ProjectionDefinitionConfiguration projectionConfiguration =
        configuration.projectionConfiguration();

    for (TemplateVariable variable : variables) {

      // Skip projection parameter
      if (projectionConfiguration.getParameterName().equals(variable.getName())) {
        continue;
      }

      ResourceDescription description =
          SimpleResourceDescription.defaultFor(variable.getDescription());

      descriptors.add( //
          descriptor()
              . //
              name(variable.getName())
              . //
              type(Type.SEMANTIC)
              . //
              doc(getDocFor(description))
              . //
              build());
    }

    return descriptors;
  }
    /**
     * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result. {@link
     * #getTransactionAttribute} is effectively a caching decorator for this method.
     *
     * @see #getTransactionAttribute
     */
    private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
      // Don't allow no-public methods as required.
      if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
      }

      // Ignore CGLIB subclasses - introspect the actual user class.
      Class<?> userClass = ClassUtils.getUserClass(targetClass);
      // The method may be on an interface, but we need attributes from the target class.
      // If the target class is null, the method will be unchanged.
      Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
      // If we are dealing with method with generic parameters, find the original method.
      specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

      TransactionAttribute txAtt = null;

      if (specificMethod != method) {
        // Fallback is to look at the original method.
        txAtt = findTransactionAttribute(method);
        if (txAtt != null) {
          return txAtt;
        }
        // Last fallback is the class of the original method.
        txAtt = findTransactionAttribute(method.getDeclaringClass());

        if (txAtt != null || !enableDefaultTransactions) {
          return txAtt;
        }
      }

      // Start: Implementation class check block

      // First try is the method in the target class.
      txAtt = findTransactionAttribute(specificMethod);
      if (txAtt != null) {
        return txAtt;
      }

      // Second try is the transaction attribute on the target class.
      txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
      if (txAtt != null) {
        return txAtt;
      }

      if (!enableDefaultTransactions) {
        return null;
      }

      // Fallback to implementation class transaction settings of nothing found
      // return findTransactionAttribute(method);
      Method targetClassMethod = repositoryInformation.getTargetClassMethod(method);

      if (targetClassMethod.equals(method)) {
        return null;
      }

      txAtt = findTransactionAttribute(targetClassMethod);
      if (txAtt != null) {
        return txAtt;
      }

      txAtt = findTransactionAttribute(targetClassMethod.getDeclaringClass());
      if (txAtt != null) {
        return txAtt;
      }

      return null;
      // End: Implementation class check block
    }