private Descriptor buildCollectionResourceDescriptor(
      Class<?> type,
      RootResourceInformation resourceInformation,
      Descriptor representationDescriptor,
      HttpMethod method) {

    ResourceMetadata metadata = mappings.getMetadataFor(type);

    List<Descriptor> nestedDescriptors = new ArrayList<Descriptor>();
    nestedDescriptors.addAll(getPaginationDescriptors(type, method));
    nestedDescriptors.addAll(getProjectionDescriptor(type, method));

    Type descriptorType = getType(method);
    return descriptor()
        . //
        id(prefix(method).concat(metadata.getRel()))
        . //
        name(metadata.getRel())
        . //
        type(descriptorType)
        . //
        doc(getDocFor(metadata.getDescription()))
        . //
        rt("#" + representationDescriptor.getId())
        . //
        descriptors(nestedDescriptors)
        .build();
  }
  /** @see DATAREST-791 */
  @Test
  public void usesRepositoryInvokerToLookupRelatedInstance() throws Exception {

    KeyValuePersistentEntity<?> entity = mappingContext.getPersistentEntity(Sample.class);

    ResourceMappings mappings =
        new PersistentEntitiesResourceMappings(
            new PersistentEntities(Collections.singleton(mappingContext)));
    ResourceMetadata metadata = spy(mappings.getMetadataFor(Sample.class));
    when(metadata.getSupportedHttpMethods()).thenReturn(AllSupportedHttpMethods.INSTANCE);

    RepositoryPropertyReferenceController controller =
        new RepositoryPropertyReferenceController(repositories, invokerFactory, assembler);
    controller.setApplicationEventPublisher(publisher);

    doReturn(invoker).when(invokerFactory).getInvokerFor(Reference.class);
    doReturn(new Sample()).when(invoker).invokeFindOne(4711);
    doReturn(new Reference()).when(invoker).invokeFindOne("some-id");
    doReturn(new Sample()).when(invoker).invokeSave(any(Object.class));

    RootResourceInformation information = new RootResourceInformation(metadata, entity, invoker);
    Resources<Object> request =
        new Resources<Object>(Collections.emptySet(), new Link("/reference/some-id"));

    controller.createPropertyReference(information, HttpMethod.POST, request, 4711, "references");

    verify(invokerFactory).getInvokerFor(Reference.class);
    verify(invoker).invokeFindOne("some-id");
  }
  private List<Descriptor> getProjectionDescriptor(Class<?> type, HttpMethod method) {

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

    ProjectionDefinitionConfiguration projectionConfiguration =
        configuration.projectionConfiguration();

    return projectionConfiguration.hasProjectionFor(type)
        ? Arrays.asList(buildProjectionDescriptor(mappings.getMetadataFor(type)))
        : Collections.<Descriptor>emptyList();
  }
  private Descriptor buildRepresentationDescriptor(Class<?> type) {

    ResourceMetadata metadata = mappings.getMetadataFor(type);

    return descriptor()
        . //
        id(getRepresentationDescriptorId(metadata))
        . //
        href(entityLinks.linkFor(type).slash("schema").toString())
        . //
        doc(getDocFor(metadata.getItemResourceDescription()))
        . //
        descriptors(buildPropertyDescriptors(type, metadata.getItemResourceRel()))
        . //
        build();
  }
  private Collection<Descriptor> buildSearchResourceDescriptors(PersistentEntity<?, ?> entity) {

    ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());
    List<Descriptor> descriptors = new ArrayList<Descriptor>();

    for (MethodResourceMapping methodMapping : metadata.getSearchResourceMappings()) {

      List<Descriptor> parameterDescriptors = new ArrayList<Descriptor>();

      for (ParameterMetadata parameterMetadata : methodMapping.getParametersMetadata()) {

        parameterDescriptors.add( //
            descriptor()
                . //
                name(parameterMetadata.getName())
                . //
                doc(getDocFor(parameterMetadata.getDescription()))
                . //
                type(Type.SEMANTIC) //
                .build());
      }

      descriptors.add(
          descriptor()
              . //
              type(Type.SAFE)
              . //
              name(methodMapping.getRel())
              . //
              descriptors(parameterDescriptors)
              . //
              build());
    }

    return descriptors;
  }
  private Descriptor buildItemResourceDescriptor(
      RootResourceInformation resourceInformation,
      Descriptor representationDescriptor,
      HttpMethod method) {

    PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
    ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());

    return descriptor()
        . //
        id(prefix(method).concat(metadata.getItemResourceRel()))
        . //
        name(metadata.getItemResourceRel())
        . //
        type(getType(method))
        . //
        doc(getDocFor(metadata.getItemResourceDescription()))
        . //
        rt("#".concat(representationDescriptor.getId()))
        . //
        descriptors(getProjectionDescriptor(entity.getType(), method))
        . //
        build();
  }
  private List<Descriptor> buildPropertyDescriptors(final Class<?> type, String baseRel) {

    final PersistentEntity<?, ?> entity = persistentEntities.getPersistentEntity(type);
    final List<Descriptor> propertyDescriptors = new ArrayList<Descriptor>();
    final JacksonMetadata jackson = new JacksonMetadata(mapper, type);
    final AssociationLinks associationLinks = new AssociationLinks(mappings);
    final ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());

    entity.doWithProperties(
        new SimplePropertyHandler() {

          @Override
          public void doWithPersistentProperty(PersistentProperty<?> property) {

            BeanPropertyDefinition propertyDefinition = jackson.getDefinitionFor(property);
            ResourceMapping propertyMapping = metadata.getMappingFor(property);

            if (propertyDefinition != null) {

              if (property.isIdProperty()
                  && !configuration.isIdExposedFor(property.getOwner().getType())) {
                return;
              }

              propertyDescriptors.add( //
                  descriptor()
                      . //
                      type(Type.SEMANTIC)
                      . //
                      name(propertyDefinition.getName())
                      . //
                      doc(getDocFor(propertyMapping.getDescription()))
                      . //
                      build());
            }
          }
        });

    entity.doWithAssociations(
        new SimpleAssociationHandler() {

          @Override
          public void doWithAssociation(Association<? extends PersistentProperty<?>> association) {

            PersistentProperty<?> property = association.getInverse();

            if (!jackson.isExported(property)
                || !associationLinks.isLinkableAssociation(property)) {
              return;
            }

            ResourceMapping mapping = metadata.getMappingFor(property);

            DescriptorBuilder builder =
                descriptor()
                    . //
                    name(mapping.getRel())
                    .doc(getDocFor(mapping.getDescription()));

            ResourceMetadata targetTypeMetadata = mappings.getMetadataFor(property.getActualType());
            String localPath =
                targetTypeMetadata
                    .getRel()
                    .concat("#")
                    .concat(getRepresentationDescriptorId(targetTypeMetadata));
            Link link =
                ControllerLinkBuilder.linkTo(AlpsController.class)
                    .slash(AlpsController.ALPS_ROOT_MAPPING)
                    .slash(localPath)
                    .withSelfRel();

            builder
                . //
                type(Type.SAFE)
                . //
                rt(link.getHref());

            propertyDescriptors.add(builder.build());
          }
        });

    return propertyDescriptors;
  }