/* * 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; } }