DATAREST-233 - Introduced @RepositoryRestResource.
@RepositoryRestResource exposes more detailed attributes tailored to the use case of exposing a repository. @RestResource is still recognized on repository interfaces but we now issue a warning and indicate the new annotation to be used. Introduced a minimal ResourceDescription interface and let @Description be used within @RestResource and @RepositoryRestResource. We now generate default resource bundle keys and resolve them against a "rest-messages" resource bundle by default. JsonSchema converter now uses the rendered descriptions for schema descriptions.
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -6,10 +22,19 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to descibe semantics of a resource.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Description {
|
||||
|
||||
/**
|
||||
* The textual description of the resource. Can be a resource bundle key for internationalization.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2014 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotate a {@link org.springframework.data.repository.Repository} with this to customize export mapping and rels.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface RepositoryRestResource {
|
||||
|
||||
/**
|
||||
* Flag indicating whether this resource is exported at all.
|
||||
*
|
||||
* @return {@literal true} if the resource is to be exported, {@literal false} otherwise.
|
||||
*/
|
||||
boolean exported() default true;
|
||||
|
||||
/**
|
||||
* The path segment under which this resource is to be exported.
|
||||
*
|
||||
* @return A valid path segment.
|
||||
*/
|
||||
String path() default "";
|
||||
|
||||
/**
|
||||
* The rel value to use when generating links to the collection resource.
|
||||
*
|
||||
* @return A valid rel value.
|
||||
*/
|
||||
String collectionResourceRel() default "";
|
||||
|
||||
/**
|
||||
* The description of the collection resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Description collectionResourceDescription() default @Description(value = "");
|
||||
|
||||
/**
|
||||
* The rel value to use when generating links to the item resource.
|
||||
*
|
||||
* @return A valid rel value.
|
||||
*/
|
||||
String itemResourceRel() default "";
|
||||
|
||||
/**
|
||||
* The description of the item resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Description itemResourceDescription() default @Description(value = "");
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -9,8 +24,12 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Annotate a {@link org.springframework.data.repository.Repository} with this to influence how it is exported and what
|
||||
* the value of the {@literal rel} attribute will be in links.
|
||||
* <p>
|
||||
* As of Spring Data REST 2.0, prefer using {@link RepositoryRestResource} to also be able to customize the relation
|
||||
* type and description for the item resources exposed by the repository.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -38,4 +57,10 @@ public @interface RestResource {
|
||||
*/
|
||||
String rel() default "";
|
||||
|
||||
/**
|
||||
* The description of the collection resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Description description() default @Description(value = "");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014 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.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link ResourceDescription} that is customized based on a {@link Description} annotation. Allows to fall back on
|
||||
* another {@link ResourceDescription} to provide defaults.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class AnnotationBasedResourceDescription extends ResolvableResourceDescriptionSupport {
|
||||
|
||||
private final String message;
|
||||
private final ResourceDescription fallback;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedResourceDescription} for the given {@link Description} and fallback.
|
||||
*
|
||||
* @param description must not be {@literal null}.
|
||||
* @param fallback must not be {@literal null}.
|
||||
*/
|
||||
AnnotationBasedResourceDescription(Description description, ResourceDescription fallback) {
|
||||
|
||||
Assert.notNull(description, "Description must not be null!");
|
||||
Assert.notNull(fallback, "Fallback resource description must not be null!");
|
||||
|
||||
this.message = description.value();
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return StringUtils.hasText(message) ? message : fallback.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mediaType
|
||||
*/
|
||||
public MediaType getType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceDescription#isDefault()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDefault() {
|
||||
return !StringUtils.hasText(message);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -22,5 +22,17 @@ package org.springframework.data.rest.core.mapping;
|
||||
*/
|
||||
public interface CollectionResourceMapping extends ResourceMapping {
|
||||
|
||||
String getSingleResourceRel();
|
||||
/**
|
||||
* Returns the relation type pointing to the item resource within a collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getItemResourceRel();
|
||||
|
||||
/**
|
||||
* Returns the {@link ResourceDescription} for the item resource.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ResourceDescription getItemResourceDescription();
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
public boolean isExported() {
|
||||
return mapping.isExported();
|
||||
}
|
||||
|
||||
@@ -129,8 +129,8 @@ class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
return mapping.getSingleResourceRel();
|
||||
public String getItemResourceRel() {
|
||||
return mapping.getItemResourceRel();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -151,6 +151,24 @@ class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
return mapping.isPagingResource();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getDescription() {
|
||||
return mapping.getDescription();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getItemResourceDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getItemResourceDescription() {
|
||||
return mapping.getItemResourceDescription();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMetadata#getSearchResourceMappings()
|
||||
|
||||
@@ -17,9 +17,12 @@ package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
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.data.rest.core.support.RepositoriesUtils;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
@@ -37,9 +40,11 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final boolean EVO_INFLECTOR_IS_PRESENT = ClassUtils.isPresent("org.atteo.evo.inflector.English", null);
|
||||
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 repositoryIsExportCandidate;
|
||||
private final RepositoryMetadata metadata;
|
||||
@@ -66,11 +71,18 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
Assert.notNull(relProvider, "RelProvider must not be null!");
|
||||
|
||||
this.annotation = AnnotationUtils.findAnnotation(repositoryType, RestResource.class);
|
||||
this.repositoryAnnotation = AnnotationUtils.findAnnotation(repositoryType, RepositoryRestResource.class);
|
||||
this.repositoryIsExportCandidate = Modifier.isPublic(repositoryType.getModifiers());
|
||||
|
||||
Class<?> domainType = RepositoriesUtils.getDomainType(repositoryType);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -80,8 +92,19 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
return annotation == null || !StringUtils.hasText(annotation.path()) ? domainTypeMapping.getPath() : new Path(
|
||||
annotation.path());
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,7 +113,20 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
*/
|
||||
@Override
|
||||
public String getRel() {
|
||||
return annotation == null || !StringUtils.hasText(annotation.rel()) ? domainTypeMapping.getRel() : annotation.rel();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -98,8 +134,16 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
return domainTypeMapping.getSingleResourceRel();
|
||||
public String getItemResourceRel() {
|
||||
|
||||
String fallback = domainTypeMapping.getItemResourceRel();
|
||||
|
||||
if (repositoryAnnotation != null) {
|
||||
String rel = repositoryAnnotation.itemResourceRel();
|
||||
return StringUtils.hasText(rel) ? rel : fallback;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -107,8 +151,17 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return annotation == null ? repositoryIsExportCandidate && domainTypeMapping.isExported() : annotation.exported();
|
||||
public boolean isExported() {
|
||||
|
||||
if (repositoryAnnotation != null) {
|
||||
return repositoryAnnotation.exported();
|
||||
}
|
||||
|
||||
if (annotation != null) {
|
||||
return annotation.exported();
|
||||
}
|
||||
|
||||
return repositoryIsExportCandidate && domainTypeMapping.isExported();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -119,4 +172,36 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
public boolean isExported() {
|
||||
return isExported;
|
||||
}
|
||||
|
||||
@@ -138,4 +138,13 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
public boolean isPagingResource() {
|
||||
return paging;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getDescription() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class ResolvableResourceDescriptionSupport implements ResourceDescription {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.MessageSourceResolvable#getCodes()
|
||||
*/
|
||||
@Override
|
||||
public String[] getCodes() {
|
||||
return new String[] { getMessage() };
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.MessageSourceResolvable#getArguments()
|
||||
*/
|
||||
@Override
|
||||
public Object[] getArguments() {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.MessageSourceResolvable#getDefaultMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getDefaultMessage() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2014 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.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* A description of a resource. Resolvable to plain text by using a {@link MessageSource}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceDescription extends MessageSourceResolvable {
|
||||
|
||||
/**
|
||||
* Returns the description. This can be a message source code or a custom text format. Prefer resolving the
|
||||
* {@link ResourceDescription} using a {@link MessageSource}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getMessage();
|
||||
|
||||
/**
|
||||
* Returns whether this is the default description.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isDefault();
|
||||
|
||||
MediaType getType();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -29,7 +29,7 @@ public interface ResourceMapping {
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
Boolean isExported();
|
||||
boolean isExported();
|
||||
|
||||
/**
|
||||
* Returns the relation for the resource exported.
|
||||
@@ -51,4 +51,11 @@ public interface ResourceMapping {
|
||||
* @return
|
||||
*/
|
||||
boolean isPagingResource();
|
||||
|
||||
/**
|
||||
* Returns the resource's description.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ResourceDescription getDescription();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.support.RepositoriesUtils;
|
||||
@@ -222,7 +223,8 @@ public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
}
|
||||
|
||||
ResourceMetadata propertyTypeMapping = getMappingFor(property.getActualType());
|
||||
propertyMapping = new PersistentPropertyResourceMapping(property, propertyTypeMapping);
|
||||
ResourceMetadata ownerTypeMapping = getMappingFor(property.getOwner().getType());
|
||||
propertyMapping = new PersistentPropertyResourceMapping(property, propertyTypeMapping, ownerTypeMapping);
|
||||
|
||||
propertyCache.put(property, propertyMapping);
|
||||
|
||||
@@ -257,7 +259,9 @@ public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
|
||||
private final PersistentProperty<?> property;
|
||||
private final ResourceMapping typeMapping;
|
||||
private final CollectionResourceMapping ownerTypeMapping;
|
||||
private final RestResource annotation;
|
||||
private final Description description;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyResourceMapping}.
|
||||
@@ -265,12 +269,16 @@ public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
* @param property must not be {@literal null}.
|
||||
* @param exported whether the property is exported or not.
|
||||
*/
|
||||
public PersistentPropertyResourceMapping(PersistentProperty<?> property, ResourceMapping typeMapping) {
|
||||
public PersistentPropertyResourceMapping(PersistentProperty<?> property, ResourceMapping typeMapping,
|
||||
CollectionResourceMapping ownerTypeMapping) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
this.property = property;
|
||||
this.typeMapping = typeMapping;
|
||||
this.annotation = property.findAnnotation(RestResource.class);
|
||||
this.ownerTypeMapping = ownerTypeMapping;
|
||||
this.annotation = property.isAssociation() ? property.findAnnotation(RestResource.class) : null;
|
||||
this.description = property.findAnnotation(Description.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -297,7 +305,7 @@ public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
public boolean isExported() {
|
||||
|
||||
if (typeMapping == null) {
|
||||
return false;
|
||||
@@ -314,5 +322,26 @@ public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
public boolean isPagingResource() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getDescription() {
|
||||
|
||||
ResourceDescription fallback = SimpleResourceDescription.defaultFor(property,
|
||||
ownerTypeMapping.getItemResourceRel());
|
||||
|
||||
if (description != null) {
|
||||
return new AnnotationBasedResourceDescription(description, fallback);
|
||||
}
|
||||
|
||||
if (annotation != null) {
|
||||
return new AnnotationBasedResourceDescription(annotation.description(), fallback);
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -100,7 +100,7 @@ public class SearchResourceMappings implements Iterable<MethodResourceMapping>,
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
public boolean isExported() {
|
||||
return !mappings.isEmpty();
|
||||
}
|
||||
|
||||
@@ -113,6 +113,15 @@ public class SearchResourceMappings implements Iterable<MethodResourceMapping>,
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2014 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.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleResourceDescription extends ResolvableResourceDescriptionSupport {
|
||||
|
||||
private static final String DEFAULT_KEY_PREFIX = "rest.description";
|
||||
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.TEXT_PLAIN;
|
||||
|
||||
private String message;
|
||||
private MediaType type;
|
||||
|
||||
private SimpleResourceDescription(String message, MediaType mediaType) {
|
||||
this.message = message;
|
||||
this.type = mediaType;
|
||||
}
|
||||
|
||||
public static ResourceDescription defaultFor(PersistentProperty<?> property, String rel) {
|
||||
|
||||
String message = String.format("%s.%s.%s", DEFAULT_KEY_PREFIX, rel, property.getName());
|
||||
return new SimpleResourceDescription(message, DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
public static ResourceDescription defaultFor(String rel) {
|
||||
|
||||
String message = String.format("%s.%s", DEFAULT_KEY_PREFIX, rel);
|
||||
return new SimpleResourceDescription(message, DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
public static ResourceDescription defaultForCollection(Class<?> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ResourceDescription defaultForMethod(RepositoryMethodResourceMapping mapping) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public MediaType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
return StringUtils.hasText(message) && message.startsWith(DEFAULT_KEY_PREFIX);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
@@ -34,8 +35,9 @@ import org.springframework.util.StringUtils;
|
||||
class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final Class<?> type;
|
||||
private final RestResource annotation;
|
||||
private final RelProvider relProvider;
|
||||
private final RestResource annotation;
|
||||
private final Description description;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeBasedCollectionResourceMapping} using the given type.
|
||||
@@ -60,6 +62,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
this.type = type;
|
||||
this.relProvider = relProvider;
|
||||
this.annotation = AnnotationUtils.findAnnotation(type, RestResource.class);
|
||||
this.description = AnnotationUtils.findAnnotation(type, Description.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -79,7 +82,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
public boolean isExported() {
|
||||
return annotation == null ? Modifier.isPublic(type.getModifiers()) : annotation.exported();
|
||||
}
|
||||
|
||||
@@ -102,7 +105,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
public String getItemResourceRel() {
|
||||
return relProvider.getSingleResourceRelFor(type);
|
||||
}
|
||||
|
||||
@@ -115,6 +118,38 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getDescription() {
|
||||
|
||||
ResourceDescription fallback = SimpleResourceDescription.defaultFor(getRel());
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getItemResourceDescription()
|
||||
*/
|
||||
@Override
|
||||
public ResourceDescription getItemResourceDescription() {
|
||||
|
||||
ResourceDescription fallback = SimpleResourceDescription.defaultFor(getItemResourceRel());
|
||||
|
||||
if (annotation != null && StringUtils.hasText(annotation.description().value())) {
|
||||
return new AnnotationBasedResourceDescription(annotation.description(), fallback);
|
||||
}
|
||||
|
||||
if (description != null) {
|
||||
return new AnnotationBasedResourceDescription(description, fallback);
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default path to be used if the path is not configured manually.
|
||||
*
|
||||
@@ -122,6 +157,10 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
* @return
|
||||
*/
|
||||
protected String getDefaultPathFor(Class<?> type) {
|
||||
return getSimpleTypeName(type);
|
||||
}
|
||||
|
||||
private String getSimpleTypeName(Class<?> type) {
|
||||
return StringUtils.uncapitalize(type.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -17,8 +17,11 @@ package org.springframework.data.rest.core.support;
|
||||
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link RelProvider} based on the {@link ResourceMappings} for the registered repositories.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryRelProvider implements RelProvider {
|
||||
@@ -26,11 +29,13 @@ public class RepositoryRelProvider implements RelProvider {
|
||||
private final ResourceMappings mappings;
|
||||
|
||||
/**
|
||||
* @param repositories
|
||||
* @param config
|
||||
* Creates a new {@link RepositoryRelProvider} for the given {@link ResourceMappings}.
|
||||
*
|
||||
* @param mappings must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryRelProvider(ResourceMappings mappings) {
|
||||
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
@@ -49,7 +54,7 @@ public class RepositoryRelProvider implements RelProvider {
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRelFor(Class<?> type) {
|
||||
return mappings.getMappingFor(type).getSingleResourceRel();
|
||||
return mappings.getMappingFor(type).getItemResourceRel();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.domain.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
@@ -7,6 +22,7 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
@@ -15,8 +31,9 @@ import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RestResource(rel = "people", path = "people")
|
||||
@RepositoryRestResource(collectionResourceRel = "people", path = "people")
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
|
||||
|
||||
@RestResource(rel = "firstname", path = "firstname")
|
||||
@@ -29,9 +46,9 @@ public interface PersonRepository extends PagingAndSortingRepository<Person, Lon
|
||||
Pageable pageable);
|
||||
|
||||
/**
|
||||
* @see DATAREST-107 - this method matches the earlier one, causing an ambiguous mapping
|
||||
* except for the exported setting
|
||||
* @see DATAREST-107 - this method matches the earlier one, causing an ambiguous mapping except for the exported
|
||||
* setting
|
||||
*/
|
||||
@RestResource(rel = "firstname", path="firstname", exported = false)
|
||||
@RestResource(rel = "firstname", path = "firstname", exported = false)
|
||||
Person findByFirstName(@Param("firstName") String firstName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -17,19 +17,18 @@ package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings.PersistentPropertyResourceMapping;
|
||||
|
||||
@@ -42,14 +41,6 @@ import org.springframework.data.rest.core.mapping.ResourceMappings.PersistentPro
|
||||
public class PersistentPropertyResourceMappingUnitTests {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(Entity.class);
|
||||
|
||||
@Mock ResourceMapping typeMapping;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(typeMapping.isExported()).thenReturn(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-175
|
||||
@@ -57,13 +48,12 @@ public class PersistentPropertyResourceMappingUnitTests {
|
||||
@Test
|
||||
public void usesPropertyNameAsDefaultResourceMappingRelAndPath() {
|
||||
|
||||
MongoPersistentProperty persistentProperty = persistentEntity.getPersistentProperty("first");
|
||||
ResourceMapping propertyMapping = new PersistentPropertyResourceMapping(persistentProperty, typeMapping);
|
||||
ResourceMapping mapping = getPropertyMappingFor(Entity.class, "first");
|
||||
|
||||
assertThat(propertyMapping, is(notNullValue()));
|
||||
assertThat(propertyMapping.getPath(), is(new Path("first")));
|
||||
assertThat(propertyMapping.getRel(), is("first"));
|
||||
assertThat(propertyMapping.isExported(), is(true));
|
||||
assertThat(mapping, is(notNullValue()));
|
||||
assertThat(mapping.getPath(), is(new Path("first")));
|
||||
assertThat(mapping.getRel(), is("first"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,13 +62,12 @@ public class PersistentPropertyResourceMappingUnitTests {
|
||||
@Test
|
||||
public void considersMappingAnnotationOnDomainClassProperty() {
|
||||
|
||||
MongoPersistentProperty persistentProperty = persistentEntity.getPersistentProperty("second");
|
||||
ResourceMapping propertyMapping = new PersistentPropertyResourceMapping(persistentProperty, typeMapping);
|
||||
ResourceMapping mapping = getPropertyMappingFor(Entity.class, "second");
|
||||
|
||||
assertThat(propertyMapping, is(notNullValue()));
|
||||
assertThat(propertyMapping.getPath(), is(new Path("secPath")));
|
||||
assertThat(propertyMapping.getRel(), is("secRel"));
|
||||
assertThat(propertyMapping.isExported(), is(false));
|
||||
assertThat(mapping, is(notNullValue()));
|
||||
assertThat(mapping.getPath(), is(new Path("secPath")));
|
||||
assertThat(mapping.getRel(), is("secRel"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,29 +76,67 @@ public class PersistentPropertyResourceMappingUnitTests {
|
||||
@Test
|
||||
public void considersMappingAnnotationOnDomainClassPropertyMethod() {
|
||||
|
||||
MongoPersistentProperty persistentProperty = persistentEntity.getPersistentProperty("third");
|
||||
ResourceMapping propertyMapping = new PersistentPropertyResourceMapping(persistentProperty, typeMapping);
|
||||
ResourceMapping mapping = getPropertyMappingFor(Entity.class, "third");
|
||||
|
||||
assertThat(propertyMapping, is(notNullValue()));
|
||||
assertThat(propertyMapping.getPath(), is(new Path("thirdPath")));
|
||||
assertThat(propertyMapping.getRel(), is("thirdRel"));
|
||||
assertThat(propertyMapping.isExported(), is(false));
|
||||
assertThat(mapping, is(notNullValue()));
|
||||
assertThat(mapping.getPath(), is(new Path("thirdPath")));
|
||||
assertThat(mapping.getRel(), is("thirdRel"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
static class Entity {
|
||||
@Test
|
||||
public void returnsDefaultDescriptionKey() {
|
||||
|
||||
Related first, third;
|
||||
ResourceMapping mapping = getPropertyMappingFor(Entity.class, "second");
|
||||
|
||||
ResourceDescription description = mapping.getDescription();
|
||||
|
||||
assertThat(description.isDefault(), is(true));
|
||||
assertThat(description.getMessage(), is("rest.description.entity.second"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-???
|
||||
*/
|
||||
@Test
|
||||
public void considersAtDescription() {
|
||||
|
||||
ResourceMapping mapping = getPropertyMappingFor(Entity.class, "fourth");
|
||||
|
||||
ResourceDescription description = mapping.getDescription();
|
||||
assertThat(description.isDefault(), is(false));
|
||||
assertThat(description.getMessage(), is("Some description"));
|
||||
}
|
||||
|
||||
private ResourceMapping getPropertyMappingFor(Class<?> entity, String propertyName) {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entity);
|
||||
MongoPersistentProperty property = persistentEntity.getPersistentProperty(propertyName);
|
||||
|
||||
CollectionResourceMapping entityResourceMapping = new TypeBasedCollectionResourceMapping(entity);
|
||||
ResourceMapping propertyTypeMapping = new TypeBasedCollectionResourceMapping(property.getType());
|
||||
|
||||
return new PersistentPropertyResourceMapping(property, propertyTypeMapping, entityResourceMapping);
|
||||
}
|
||||
|
||||
public static class Entity {
|
||||
|
||||
Related first;
|
||||
@DBRef Related third;
|
||||
|
||||
@DBRef//
|
||||
@RestResource(path = "secPath", rel = "secRel", exported = false)//
|
||||
List<Related> second;
|
||||
|
||||
@Description("Some description") String fourth;
|
||||
|
||||
@RestResource(path = "thirdPath", rel = "thirdRel", exported = false)
|
||||
public Related getThird() {
|
||||
return third;
|
||||
}
|
||||
}
|
||||
|
||||
static class Related {
|
||||
public static class Related {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
|
||||
/**
|
||||
@@ -41,7 +42,7 @@ public class RepositoryCollectionResourceMappingUnitTests {
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("persons")));
|
||||
assertThat(mapping.getRel(), is("persons"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person"));
|
||||
assertThat(mapping.getItemResourceRel(), is("person"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ public class RepositoryCollectionResourceMappingUnitTests {
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("bar")));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.getItemResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ public class RepositoryCollectionResourceMappingUnitTests {
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("/trumpsAll")));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.getItemResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@@ -82,6 +83,14 @@ public class RepositoryCollectionResourceMappingUnitTests {
|
||||
assertThat(getResourceMappingFor(PersonRepository.class).isPagingResource(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoversCustomizationsUsingRestRepositoryResource() {
|
||||
|
||||
CollectionResourceMapping mapping = getResourceMappingFor(RepositoryAnnotatedRepository.class);
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getItemResourceRel(), is("bar"));
|
||||
}
|
||||
|
||||
private static CollectionResourceMapping getResourceMappingFor(Class<?> repositoryInterface) {
|
||||
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface);
|
||||
@@ -106,4 +115,7 @@ public class RepositoryCollectionResourceMappingUnitTests {
|
||||
public static class PublicClass {}
|
||||
|
||||
interface PackageProtectedRepository extends Repository<PublicClass, Long> {}
|
||||
|
||||
@RepositoryRestResource(collectionResourceRel = "foo", itemResourceRel = "bar")
|
||||
interface RepositoryAnnotatedRepository extends Repository<Person, Long> {}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class ResourceMappingsIntegrationTest {
|
||||
public class ResourceMappingsIntegrationTests {
|
||||
|
||||
@Autowired ListableBeanFactory factory;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -21,15 +21,13 @@ import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.data.rest.core.mapping.CollectionResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.TypeBasedCollectionResourceMapping;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TypeBasedCollectionResourceMapping}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class TypeBasedCollectionResourceMappingUnitTest {
|
||||
public class TypeBasedCollectionResourceMappingUnitTests {
|
||||
|
||||
@Test
|
||||
public void defaultsMappingsByType() {
|
||||
@@ -38,7 +36,7 @@ public class TypeBasedCollectionResourceMappingUnitTest {
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("sample")));
|
||||
assertThat(mapping.getRel(), is("samples"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("sample"));
|
||||
assertThat(mapping.getItemResourceRel(), is("sample"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@@ -49,7 +47,7 @@ public class TypeBasedCollectionResourceMappingUnitTest {
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("customizedSample")));
|
||||
assertThat(mapping.getRel(), is("myRel"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("customizedSample"));
|
||||
assertThat(mapping.getItemResourceRel(), is("customizedSample"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@@ -64,6 +62,24 @@ public class TypeBasedCollectionResourceMappingUnitTest {
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see
|
||||
*/
|
||||
@Test
|
||||
public void usesDefaultDescriptionIfNoAnnotationPresent() {
|
||||
|
||||
CollectionResourceMapping mapping = new TypeBasedCollectionResourceMapping(Sample.class);
|
||||
ResourceDescription description = mapping.getDescription();
|
||||
|
||||
assertThat(description.isDefault(), is(true));
|
||||
assertThat(description.getMessage(), is("rest.description.samples"));
|
||||
|
||||
ResourceDescription itemDescription = mapping.getItemResourceDescription();
|
||||
|
||||
assertThat(itemDescription.isDefault(), is(true));
|
||||
assertThat(itemDescription.getMessage(), is("rest.description.sample"));
|
||||
}
|
||||
|
||||
public interface Sample {}
|
||||
|
||||
interface HiddenSample {}
|
||||
@@ -7,7 +7,7 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.data" level="error" />
|
||||
<logger name="org.springframework.data" level="warn" />
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="console" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -200,7 +200,7 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
ResourceMetadata repoMapping = repoRequest.getResourceMetadata();
|
||||
|
||||
Link selfLink = resource.getLink("self");
|
||||
String rel = repoMapping.getSingleResourceRel();
|
||||
String rel = repoMapping.getItemResourceRel();
|
||||
|
||||
return new Link(selfLink.getHref(), rel);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -30,6 +30,8 @@ import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.data.repository.support.DomainClassConverter;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
@@ -39,6 +41,7 @@ import org.springframework.data.rest.core.event.AnnotatedHandlerBeanPostProcesso
|
||||
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
|
||||
import org.springframework.data.rest.core.invoke.DefaultRepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.invoke.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.mapping.ResourceDescription;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.support.DomainObjectMerger;
|
||||
import org.springframework.data.rest.core.util.UUIDConverter;
|
||||
@@ -268,7 +271,23 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
*/
|
||||
@Bean
|
||||
public PersistentEntityToJsonSchemaConverter jsonSchemaConverter() {
|
||||
return new PersistentEntityToJsonSchemaConverter(repositories(), resourceMappings());
|
||||
return new PersistentEntityToJsonSchemaConverter(repositories(), resourceMappings(),
|
||||
resourceDescriptionMessageSourceAccessor());
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link MessageSourceAccessor} to provide messages for {@link ResourceDescription}s being rendered.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MessageSourceAccessor resourceDescriptionMessageSourceAccessor() {
|
||||
|
||||
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
|
||||
messageSource.setBasename("classpath:rest-messages");
|
||||
messageSource.setUseCodeAsDefaultMessage(true);
|
||||
|
||||
return new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.webmvc.json;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -5,16 +20,20 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.hateoas.Resource;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Model class to render JSON schema documents.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
|
||||
|
||||
private final String name;
|
||||
@SuppressWarnings("unused") private final String description;
|
||||
private final String description;
|
||||
|
||||
public JsonSchema(String name, String description) {
|
||||
super(new HashMap<String, Property>());
|
||||
@@ -26,6 +45,10 @@ public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@JsonProperty("properties")
|
||||
@Override
|
||||
public Map<String, JsonSchema.Property> getContent() {
|
||||
@@ -46,6 +69,7 @@ public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
|
||||
}
|
||||
|
||||
public static class Property {
|
||||
|
||||
private final String type;
|
||||
private final String description;
|
||||
private final boolean required;
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.webmvc.json;
|
||||
|
||||
import static org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.*;
|
||||
@@ -10,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.data.mapping.Association;
|
||||
@@ -18,9 +34,12 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.mapping.ResourceDescription;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.ArrayProperty;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.Property;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryLinkBuilder;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -37,6 +56,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
private final Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private final ResourceMappings mappings;
|
||||
private final Repositories repositories;
|
||||
private final MessageSourceAccessor accessor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityToJsonSchemaConverter} for the given {@link Repositories} and
|
||||
@@ -44,14 +64,17 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
* @param accessor
|
||||
*/
|
||||
public PersistentEntityToJsonSchemaConverter(Repositories repositories, ResourceMappings mappings) {
|
||||
public PersistentEntityToJsonSchemaConverter(Repositories repositories, ResourceMappings mappings,
|
||||
MessageSourceAccessor accessor) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.mappings = mappings;
|
||||
this.accessor = accessor;
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
convertiblePairs.add(new ConvertiblePair(domainType, JsonSchema.class));
|
||||
@@ -90,9 +113,8 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity((Class<?>) source);
|
||||
final ResourceMetadata metadata = mappings.getMappingFor(persistentEntity.getType());
|
||||
String entityDesc = persistentEntity.getType().isAnnotationPresent(Description.class) ? persistentEntity.getType()
|
||||
.getAnnotation(Description.class).value() : null;
|
||||
final JsonSchema jsonSchema = new JsonSchema(persistentEntity.getName(), entityDesc);
|
||||
final JsonSchema jsonSchema = new JsonSchema(persistentEntity.getName(), accessor.getMessage(metadata
|
||||
.getItemResourceDescription()));
|
||||
|
||||
persistentEntity.doWithProperties(new SimplePropertyHandler() {
|
||||
|
||||
@@ -106,12 +128,16 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
Class<?> propertyType = persistentProperty.getType();
|
||||
String type = uncapitalize(propertyType.getSimpleName());
|
||||
|
||||
boolean notNull = persistentProperty.isAnnotationPresent(NotNull.class);
|
||||
Description descriptionAnnotation = persistentProperty.findAnnotation(Description.class);
|
||||
String desc = descriptionAnnotation == null ? null : descriptionAnnotation.value();
|
||||
ResourceMapping propertyMapping = metadata.getMappingFor(persistentProperty);
|
||||
|
||||
boolean notNull = persistentProperty.isAnnotationPresent(NotNull.class);
|
||||
ResourceDescription description = propertyMapping.getDescription();
|
||||
String message = accessor.getMessage(description);
|
||||
|
||||
Property property = persistentProperty.isCollectionLike() ? //
|
||||
new ArrayProperty("array", message, notNull)
|
||||
: new Property(type, message, notNull);
|
||||
|
||||
JsonSchema.Property property = persistentProperty.isCollectionLike() ? new JsonSchema.ArrayProperty("array",
|
||||
desc, notNull) : new JsonSchema.Property(type, desc, notNull);
|
||||
jsonSchema.addProperty(persistentProperty.getName(), property);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.webmvc.support;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -112,6 +127,6 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
public Link linkToSingleResource(Class<?> type, Object id) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
return linkFor(type).slash(id).withRel(metadata.getSingleResourceRel());
|
||||
return linkFor(type).slash(id).withRel(metadata.getItemResourceRel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
@@ -30,8 +31,9 @@ import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RestResource(rel = "people", path = "people")
|
||||
@RepositoryRestResource(collectionResourceRel = "people", path = "people")
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
|
||||
|
||||
@RestResource(rel = "firstname", path = "firstname")
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2014 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.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.AbstractControllerIntegrationTests;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Profile;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
|
||||
public class PersistentEntityToJsonSchemaConverterUnitTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired PersistentEntityToJsonSchemaConverter converter;
|
||||
|
||||
@Test
|
||||
public void addsDescriptionToSchemaRoot() {
|
||||
|
||||
JsonSchema schema = converter.convert(Profile.class);
|
||||
|
||||
assertThat(schema.getDescription(), is("Profile description"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
rest.description.profile=Profile description
|
||||
Reference in New Issue
Block a user