/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.rest.core.mapping;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.Path;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.hateoas.core.AnnotationAttribute;
import org.springframework.hateoas.core.MethodParameters;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link RepositoryMethodResourceMapping} created from a {@link Method}.
*
* @author Oliver Gierke
*/
class RepositoryMethodResourceMapping implements MethodResourceMapping {
@SuppressWarnings("unchecked") //
private static final Collection<Class<?>> IMPLICIT_PARAMETER_TYPES = Arrays.asList(Pageable.class, Sort.class);
private static final AnnotationAttribute PARAM_VALUE = new AnnotationAttribute(Param.class);
private final boolean isExported;
private final String rel;
private final Path path;
private final Method method;
private final boolean paging;
private final boolean sorting;
private final RepositoryMetadata metadata;
private final List<ParameterMetadata> parameterMetadata;
/**
* Creates a new {@link RepositoryMethodResourceMapping} for the given {@link Method}.
*
* @param method must not be {@literal null}.
* @param resourceMapping must not be {@literal null}.
*/
public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping, RepositoryMetadata metadata) {
Assert.notNull(method, "Method must not be null!");
Assert.notNull(resourceMapping, "ResourceMapping must not be null!");
RestResource annotation = AnnotationUtils.findAnnotation(method, RestResource.class);
String resourceRel = resourceMapping.getRel();
this.isExported = annotation != null ? annotation.exported() : true;
this.rel = annotation == null || !StringUtils.hasText(annotation.rel()) ? method.getName() : annotation.rel();
this.path = annotation == null || !StringUtils.hasText(annotation.path()) ? new Path(method.getName())
: new Path(annotation.path());
this.method = method;
this.parameterMetadata = discoverParameterMetadata(method, resourceRel.concat(".").concat(rel));
List<Class<?>> parameterTypes = Arrays.asList(method.getParameterTypes());
this.paging = parameterTypes.contains(Pageable.class);
this.sorting = parameterTypes.contains(Sort.class);
this.metadata = metadata;
}
private static final List<ParameterMetadata> discoverParameterMetadata(Method method, String baseRel) {
List<ParameterMetadata> result = new ArrayList<ParameterMetadata>();
for (MethodParameter parameter : new MethodParameters(method, PARAM_VALUE).getParameters()) {
if (!IMPLICIT_PARAMETER_TYPES.contains(parameter.getParameterType())
&& StringUtils.hasText(parameter.getParameterName())) {
result.add(new ParameterMetadata(parameter, baseRel));
}
}
return Collections.unmodifiableList(result);
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
*/
@Override
public boolean isExported() {
return isExported;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel()
*/
@Override
public String getRel() {
return rel;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getPath()
*/
@Override
public Path getPath() {
return path;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.MethodResourceMapping#getMethod()
*/
@Override
public Method getMethod() {
return method;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.MethodResourceMapping#getParameterMetadata()
*/
@Override
public ParametersMetadata getParametersMetadata() {
return new ParametersMetadata(parameterMetadata);
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isPagingResource()
*/
@Override
public boolean isPagingResource() {
return paging;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.MethodResourceMapping#isSortableResource()
*/
@Override
public boolean isSortableResource() {
return sorting;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
*/
@Override
public ResourceDescription getDescription() {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.MethodResourceMapping#getProjectionSourceType()
*/
@Override
public Class<?> getReturnedDomainType() {
return metadata.getReturnedDomainClass(method);
}
}