/*
* 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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.rest.core.Path;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.core.EvoInflectorRelProvider;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* {@link CollectionResourceMapping} to be built from repository interfaces. Will inspect {@link RestResource}
* annotations on the repository interface but fall back to the mapping information of the managed domain type for
* defaults.
*
* @author Oliver Gierke
*/
class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryCollectionResourceMapping.class);
private static final boolean EVO_INFLECTOR_IS_PRESENT = ClassUtils.isPresent("org.atteo.evo.inflector.English", null);
private final RestResource annotation;
private final RepositoryRestResource repositoryAnnotation;
private final CollectionResourceMapping domainTypeMapping;
private final boolean repositoryExported;
private final RepositoryMetadata metadata;
public RepositoryCollectionResourceMapping(RepositoryMetadata metadata, RepositoryDetectionStrategy strategy) {
this(metadata, new EvoInflectorRelProvider(), strategy);
}
/**
* Creates a new {@link RepositoryCollectionResourceMapping} for the given repository using the given
* {@link RelProvider}.
*
* @param repositoryType must not be {@literal null}.
* @param relProvider must not be {@literal null}.
* @param strategy must not be {@literal null}.
*/
RepositoryCollectionResourceMapping(RepositoryMetadata metadata, RelProvider relProvider,
RepositoryDetectionStrategy strategy) {
Assert.notNull(metadata, "Repository metadata must not be null!");
Assert.notNull(relProvider, "RelProvider must not be null!");
Assert.notNull(strategy, "RepositoryDetectionStrategy must not be null!");
Class<?> repositoryType = metadata.getRepositoryInterface();
this.metadata = metadata;
this.annotation = AnnotationUtils.findAnnotation(repositoryType, RestResource.class);
this.repositoryAnnotation = AnnotationUtils.findAnnotation(repositoryType, RepositoryRestResource.class);
this.repositoryExported = strategy.isExported(metadata);
Class<?> domainType = metadata.getDomainType();
this.domainTypeMapping = EVO_INFLECTOR_IS_PRESENT
? new EvoInflectorTypeBasedCollectionResourceMapping(domainType, relProvider)
: new TypeBasedCollectionResourceMapping(domainType, relProvider);
if (annotation != null) {
LOGGER.warn(
"@RestResource detected to customize the repository resource for {}! Use @RepositoryRestResource instead!",
metadata.getRepositoryInterface().getName());
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getPath()
*/
@Override
public Path getPath() {
Path fallback = domainTypeMapping.getPath();
if (repositoryAnnotation != null) {
String path = repositoryAnnotation.path();
return StringUtils.hasText(path) ? new Path(path) : fallback;
}
if (annotation != null) {
String path = annotation.path();
return StringUtils.hasText(path) ? new Path(path) : fallback;
}
return fallback;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel()
*/
@Override
public String getRel() {
String fallback = domainTypeMapping.getRel();
if (repositoryAnnotation != null) {
String rel = repositoryAnnotation.collectionResourceRel();
return StringUtils.hasText(rel) ? rel : fallback;
}
if (annotation != null) {
String rel = annotation.rel();
return StringUtils.hasText(rel) ? rel : fallback;
}
return fallback;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel()
*/
@Override
public String getItemResourceRel() {
String fallback = domainTypeMapping.getItemResourceRel();
if (repositoryAnnotation != null) {
String rel = repositoryAnnotation.itemResourceRel();
return StringUtils.hasText(rel) ? rel : fallback;
}
return fallback;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
*/
@Override
public boolean isExported() {
return repositoryExported;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#isPagingResource()
*/
@Override
public boolean isPagingResource() {
return metadata.isPagingRepository();
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
*/
@Override
public ResourceDescription getDescription() {
ResourceDescription fallback = SimpleResourceDescription.defaultFor(getRel());
if (repositoryAnnotation != null) {
return new AnnotationBasedResourceDescription(repositoryAnnotation.collectionResourceDescription(), fallback);
}
return fallback;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getItemResourceDescription()
*/
@Override
public ResourceDescription getItemResourceDescription() {
ResourceDescription fallback = SimpleResourceDescription.defaultFor(getItemResourceRel());
if (repositoryAnnotation != null) {
return new AnnotationBasedResourceDescription(repositoryAnnotation.itemResourceDescription(), fallback);
}
return fallback;
}
/*
* (non-Javadoc)
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getExcerptProjection()
*/
@Override
public Class<?> getExcerptProjection() {
if (repositoryAnnotation == null) {
return null;
}
Class<?> excerptProjection = repositoryAnnotation.excerptProjection();
return excerptProjection.equals(RepositoryRestResource.None.class) ? null : excerptProjection;
}
}