DATAREST-774 - Separated integration tests from core project to avoid classpath overlap.
Extracted store specific tests into separate test modules to prevent classpath overlap between projects. Those tests are now executed in an "it" build profile to prevent the tests being packaged for distribution on release. Use Map-based repositories and mapping contexts for test in the Core and WebMvc module. Slightly changed the configuration API for lookup types on RepositoryRestConfiguration. Related ticket: DATAREST-776.
This commit is contained in:
@@ -29,7 +29,7 @@ import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
|
||||
import org.springframework.hateoas.core.EmbeddedWrapper;
|
||||
import org.springframework.hateoas.core.EmbeddedWrappers;
|
||||
@@ -42,14 +42,14 @@ import org.springframework.util.Assert;
|
||||
public class EmbeddedResourcesAssembler {
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull AssociationLinks associations;
|
||||
private final @NonNull Associations associations;
|
||||
private final @NonNull ExcerptProjector projector;
|
||||
private final @NonNull EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
|
||||
|
||||
/**
|
||||
* Returns the embedded resources to render. This will add an {@link RelatedResource} for linkable associations if
|
||||
* they have an excerpt projection registered.
|
||||
*
|
||||
*
|
||||
* @param instance must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2016 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,7 +22,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource.Builder;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.Projector;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.ResourceAssembler;
|
||||
@@ -40,7 +40,7 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull Projector projector;
|
||||
private final @NonNull AssociationLinks associations;
|
||||
private final @NonNull Associations associations;
|
||||
private final @NonNull SelfLinkProvider linkProvider;
|
||||
private final @NonNull EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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,7 +30,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ProfileResourceProcessor implements ResourceProcessor<RepositoryLinksResource> {
|
||||
|
||||
static final String PROFILE_REL = "profile";
|
||||
public static final String PROFILE_REL = "profile";
|
||||
|
||||
private final RepositoryRestConfiguration configuration;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -54,7 +54,7 @@ import org.springframework.data.rest.webmvc.ProfileController;
|
||||
import org.springframework.data.rest.webmvc.RootResourceInformation;
|
||||
import org.springframework.data.rest.webmvc.json.EnumTranslator;
|
||||
import org.springframework.data.rest.webmvc.json.JacksonMetadata;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.TemplateVariable;
|
||||
@@ -82,7 +82,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
|
||||
private static final List<HttpMethod> UNDOCUMENTED_METHODS = Arrays.asList(HttpMethod.OPTIONS, HttpMethod.HEAD);
|
||||
|
||||
private final @NonNull AssociationLinks associations;
|
||||
private final @NonNull Associations associations;
|
||||
private final @NonNull Repositories repositories;
|
||||
private final @NonNull PersistentEntities persistentEntities;
|
||||
private final @NonNull EntityLinks entityLinks;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -24,7 +24,7 @@ import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.rest.core.projection.ProjectionDefinitions;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.PersistentEntityProjector;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -43,7 +43,7 @@ public class PersistentEntityResourceAssemblerArgumentResolver implements Handle
|
||||
private final @NonNull SelfLinkProvider linkProvider;
|
||||
private final @NonNull ProjectionDefinitions projectionDefinitions;
|
||||
private final @NonNull ProjectionFactory projectionFactory;
|
||||
private final @NonNull AssociationLinks links;
|
||||
private final @NonNull Associations links;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -96,7 +96,7 @@ import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverter;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverter.ValueTypeSchemaPropertyCustomizerFactory;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConverter;
|
||||
@@ -232,9 +232,10 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
* {@link org.springframework.validation.Validator} instances assigned to specific domain types.
|
||||
*/
|
||||
@Bean
|
||||
public ValidatingRepositoryEventListener validatingRepositoryEventListener(ObjectFactory<Repositories> repositories) {
|
||||
public ValidatingRepositoryEventListener validatingRepositoryEventListener(
|
||||
ObjectFactory<PersistentEntities> entities) {
|
||||
|
||||
ValidatingRepositoryEventListener listener = new ValidatingRepositoryEventListener(repositories);
|
||||
ValidatingRepositoryEventListener listener = new ValidatingRepositoryEventListener(entities);
|
||||
configurerDelegate.configureValidatingRepositoryEventListener(listener);
|
||||
configureValidatingRepositoryEventListener(listener);
|
||||
|
||||
@@ -755,8 +756,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AssociationLinks associationLinks() {
|
||||
return new AssociationLinks(resourceMappings(), config());
|
||||
public Associations associationLinks() {
|
||||
return new Associations(resourceMappings(), config());
|
||||
}
|
||||
|
||||
protected List<EntityLookup<?>> getEntityLookups() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -53,7 +53,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
public class DomainObjectReader {
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull AssociationLinks associationLinks;
|
||||
private final @NonNull Associations associationLinks;
|
||||
private final @NonNull ClassIntrospector introspector = new BasicClassIntrospector();
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -44,7 +44,7 @@ import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.ResourceProcessorInvoker;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
@@ -110,7 +110,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param linkProvider must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityJackson2Module(AssociationLinks associations, PersistentEntities entities,
|
||||
public PersistentEntityJackson2Module(Associations associations, PersistentEntities entities,
|
||||
UriToEntityConverter converter, LinkCollector collector, RepositoryInvokerFactory factory,
|
||||
NestedEntitySerializer serializer, LookupObjectSerializer lookupObjectSerializer) {
|
||||
|
||||
@@ -144,7 +144,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityResourceSerializer} using the given {@link PersistentEntities} and
|
||||
* {@link AssociationLinks}.
|
||||
* {@link Associations}.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
*/
|
||||
@@ -221,7 +221,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
static class AssociationOmittingSerializerModifier extends BeanSerializerModifier {
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull AssociationLinks associations;
|
||||
private final @NonNull Associations associations;
|
||||
private final @NonNull NestedEntitySerializer nestedEntitySerializer;
|
||||
private final @NonNull LookupObjectSerializer lookupObjectSerializer;
|
||||
|
||||
@@ -378,7 +378,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
public static class AssociationUriResolvingDeserializerModifier extends BeanDeserializerModifier {
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull AssociationLinks associationLinks;
|
||||
private final @NonNull Associations associationLinks;
|
||||
private final @NonNull UriToEntityConverter converter;
|
||||
private final @NonNull RepositoryInvokerFactory factory;
|
||||
|
||||
@@ -512,7 +512,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
static class ProjectionSerializer extends StdSerializer<TargetAware> {
|
||||
|
||||
private final LinkCollector collector;
|
||||
private final AssociationLinks associations;
|
||||
private final Associations associations;
|
||||
private final boolean unwrapping;
|
||||
|
||||
/**
|
||||
@@ -523,7 +523,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
* @param mappings must not be {@literal null}.
|
||||
* @param unwrapping
|
||||
*/
|
||||
private ProjectionSerializer(LinkCollector collector, AssociationLinks mappings, boolean unwrapping) {
|
||||
private ProjectionSerializer(LinkCollector collector, Associations mappings, boolean unwrapping) {
|
||||
|
||||
super(TargetAware.class);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.springframework.data.rest.webmvc.json.JsonSchema.Definitions;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.EnumProperty;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.Item;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.JsonSchemaProperty;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -76,7 +76,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
private static final TypeInformation<?> STRING_TYPE_INFORMATION = ClassTypeInformation.from(String.class);
|
||||
|
||||
private final Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private final AssociationLinks associations;
|
||||
private final Associations associations;
|
||||
private final PersistentEntities entities;
|
||||
private final MessageSourceAccessor accessor;
|
||||
private final ObjectMapper objectMapper;
|
||||
@@ -93,7 +93,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
* @param objectMapper must not be {@literal null}.
|
||||
* @param configuration must not be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityToJsonSchemaConverter(PersistentEntities entities, AssociationLinks associations,
|
||||
public PersistentEntityToJsonSchemaConverter(PersistentEntities entities, Associations associations,
|
||||
MessageSourceAccessor accessor, ObjectMapper objectMapper, RepositoryRestConfiguration configuration,
|
||||
ValueTypeSchemaPropertyCustomizerFactory customizerFactory) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -34,14 +34,14 @@ import org.springframework.hateoas.Link;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A value object to for {@link Link}s representing an association.
|
||||
* A value object to for {@link Link}s representing associations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
* @since 2.1
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class AssociationLinks {
|
||||
public class Associations {
|
||||
|
||||
private final @NonNull @Getter ResourceMappings mappings;
|
||||
private final @NonNull RepositoryRestConfiguration config;
|
||||
@@ -39,7 +39,7 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle
|
||||
private static final String AMBIGUOUS_ASSOCIATIONS = "Detected multiple association links with same relation type! Disambiguate association %s using @RestResource!";
|
||||
|
||||
private final PersistentEntities entities;
|
||||
private final AssociationLinks associationLinks;
|
||||
private final Associations associations;
|
||||
private final Path basePath;
|
||||
private final boolean nested;
|
||||
|
||||
@@ -47,25 +47,25 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle
|
||||
|
||||
/**
|
||||
* Creates a new {@link LinkCollectingAssociationHandler} for the given {@link PersistentEntities}, {@link Path} and
|
||||
* {@link AssociationLinks}.
|
||||
* {@link Associations}.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param associationLinks must not be {@literal null}.
|
||||
* @param associations must not be {@literal null}.
|
||||
*/
|
||||
public LinkCollectingAssociationHandler(PersistentEntities entities, Path path, AssociationLinks associationLinks) {
|
||||
this(entities, path, associationLinks, false);
|
||||
public LinkCollectingAssociationHandler(PersistentEntities entities, Path path, Associations associations) {
|
||||
this(entities, path, associations, false);
|
||||
}
|
||||
|
||||
private LinkCollectingAssociationHandler(PersistentEntities entities, Path path, AssociationLinks associationLinks,
|
||||
private LinkCollectingAssociationHandler(PersistentEntities entities, Path path, Associations associations,
|
||||
boolean nested) {
|
||||
|
||||
Assert.notNull(entities, "PersistentEntities must not be null!");
|
||||
Assert.notNull(path, "Path must not be null!");
|
||||
Assert.notNull(associationLinks, "AssociationLinks must not be null!");
|
||||
Assert.notNull(associations, "AssociationLinks must not be null!");
|
||||
|
||||
this.entities = entities;
|
||||
this.associationLinks = associationLinks;
|
||||
this.associations = associations;
|
||||
this.basePath = path;
|
||||
|
||||
this.links = new ArrayList<Link>();
|
||||
@@ -73,7 +73,7 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle
|
||||
}
|
||||
|
||||
public LinkCollectingAssociationHandler nested() {
|
||||
return nested ? this : new LinkCollectingAssociationHandler(entities, basePath, associationLinks, true);
|
||||
return nested ? this : new LinkCollectingAssociationHandler(entities, basePath, associations, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,11 +94,11 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle
|
||||
|
||||
PersistentProperty<?> property = association.getInverse();
|
||||
|
||||
if (associationLinks.isLinkableAssociation(property)) {
|
||||
if (associations.isLinkableAssociation(property)) {
|
||||
|
||||
Links existingLinks = new Links(links);
|
||||
|
||||
for (Link link : associationLinks.getLinksFor(association, basePath)) {
|
||||
for (Link link : associations.getLinksFor(association, basePath)) {
|
||||
if (existingLinks.hasLink(link.getRel())) {
|
||||
throw new MappingException(String.format(AMBIGUOUS_ASSOCIATIONS, property.toString()));
|
||||
} else {
|
||||
|
||||
@@ -47,17 +47,17 @@ import org.springframework.util.Assert;
|
||||
public class LinkCollector {
|
||||
|
||||
private final PersistentEntities entities;
|
||||
private final AssociationLinks associationLinks;
|
||||
private final Associations associationLinks;
|
||||
private final SelfLinkProvider links;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntities}, {@link SelfLinkProvider} and {@link AssociationLinks}.
|
||||
*
|
||||
* Creates a new {@link PersistentEntities}, {@link SelfLinkProvider} and {@link Associations}.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param linkProvider must not be {@literal null}.
|
||||
* @param associationLinks must not be {@literal null}.
|
||||
*/
|
||||
public LinkCollector(PersistentEntities entities, SelfLinkProvider linkProvider, AssociationLinks associationLinks) {
|
||||
public LinkCollector(PersistentEntities entities, SelfLinkProvider linkProvider, Associations associationLinks) {
|
||||
|
||||
Assert.notNull(entities, "PersistentEntities must not be null!");
|
||||
Assert.notNull(linkProvider, "SelfLinkProvider must not be null!");
|
||||
@@ -70,7 +70,7 @@ public class LinkCollector {
|
||||
|
||||
/**
|
||||
* Returns all {@link Links} for the given object.
|
||||
*
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -80,7 +80,7 @@ public class LinkCollector {
|
||||
|
||||
/**
|
||||
* Returns all {@link Links} for the given object and already existing {@link Link}.
|
||||
*
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @param existingLinks must not be {@literal null}.
|
||||
* @return
|
||||
@@ -151,7 +151,7 @@ public class LinkCollector {
|
||||
|
||||
/**
|
||||
* {@link SimpleAssociationHandler} that will collect {@link Link}s for all linkable associations.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -162,19 +162,19 @@ public class LinkCollector {
|
||||
|
||||
private final @NonNull PersistentEntities entities;
|
||||
private final @NonNull Path basePath;
|
||||
private final @NonNull AssociationLinks associationLinks;
|
||||
private final @NonNull Associations associationLinks;
|
||||
private final @NonNull List<Link> links = new ArrayList<Link>();
|
||||
|
||||
/**
|
||||
* Returns the links collected after the {@link Association} has been traversed.
|
||||
*
|
||||
*
|
||||
* @return the links
|
||||
*/
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.SimpleAssociationHandler#doWithAssociation(org.springframework.data.mapping.Association)
|
||||
*/
|
||||
@@ -202,10 +202,10 @@ public class LinkCollector {
|
||||
|
||||
private final SelfLinkProvider selfLinks;
|
||||
private final PersistentPropertyAccessor accessor;
|
||||
private final AssociationLinks associations;
|
||||
private final Associations associations;
|
||||
private final @Getter List<Link> links = new ArrayList<Link>();
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.SimpleAssociationHandler#doWithAssociation(org.springframework.data.mapping.Association)
|
||||
*/
|
||||
@@ -234,7 +234,7 @@ public class LinkCollector {
|
||||
|
||||
/**
|
||||
* Returns a link pointing to the given entity using the given {@link ResourceMapping} to detect the link relation.
|
||||
*
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param mapping must not be {@literal null}.
|
||||
* @return
|
||||
@@ -246,7 +246,7 @@ public class LinkCollector {
|
||||
/**
|
||||
* Returns the given object as {@link Collection}, i.e. the object as is if it's a collection already or wrapped
|
||||
* into a single-element collection otherwise.
|
||||
*
|
||||
*
|
||||
* @param object can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.support.Projector;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Base class to write integration tests for controllers.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public abstract class AbstractControllerIntegrationTests {
|
||||
|
||||
public static final Path BASE = new Path("http://localhost");
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration extends RepositoryRestMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
public PersistentEntityResourceAssembler persistentEntityResourceAssembler() {
|
||||
|
||||
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(persistentEntities(), entityLinks(),
|
||||
Collections.<EntityLookup<?>> emptyList());
|
||||
|
||||
return new PersistentEntityResourceAssembler(persistentEntities(), StubProjector.INSTANCE, associationLinks(),
|
||||
selfLinkProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired Repositories repositories;
|
||||
@Autowired RepositoryInvokerFactory invokerFactory;
|
||||
@Autowired ResourceMappings mappings;
|
||||
|
||||
@Before
|
||||
public void initWebInfrastructure() {
|
||||
TestMvcClient.initWebTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RootResourceInformation} for the given domain type.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected RootResourceInformation getResourceInformation(Class<?> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "Domain type must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
|
||||
|
||||
return new RootResourceInformation(mappings.getMetadataFor(domainType), entity,
|
||||
invokerFactory.getInvokerFor(domainType));
|
||||
}
|
||||
|
||||
protected WebRequest getRequest(RequestParameters parameters) {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameters(parameters.asMap());
|
||||
|
||||
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
|
||||
RequestContextHolder.setRequestAttributes(requestAttributes);
|
||||
|
||||
return new ServletWebRequest(request);
|
||||
}
|
||||
|
||||
protected ResourceMetadata getMetadata(Class<?> domainType) {
|
||||
return mappings.getMetadataFor(domainType);
|
||||
}
|
||||
|
||||
private static enum StubProjector implements Projector {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Object project(Object source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object projectExcerpt(Object source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasExcerptProjection(Class<?> type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverers;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.jayway.jsonpath.InvalidPathException;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* A test harness for hypermedia unit/integration testing. Provides chained operations (like postAndGet) to create a new
|
||||
* entity and then retrieve it with a single method call. It also provides often-used assertions (like
|
||||
* assertJsonPathEquals).
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = RepositoryRestMvcConfiguration.class)
|
||||
public abstract class AbstractWebIntegrationTests {
|
||||
|
||||
private static final String CONTENT_LINK_JSONPATH = "$._embedded.._links.%s.href[0]";
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
@Autowired LinkDiscoverers discoverers;
|
||||
|
||||
protected TestMvcClient client;
|
||||
protected MockMvc mvc;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
setupMockMvc();
|
||||
this.client = new TestMvcClient(mvc, discoverers);
|
||||
}
|
||||
|
||||
protected void setupMockMvc() {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(context).//
|
||||
defaultRequest(get("/").accept(TestMvcClient.DEFAULT_MEDIA_TYPE)).build();
|
||||
}
|
||||
|
||||
protected MockHttpServletResponse postAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
|
||||
|
||||
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
|
||||
|
||||
MockHttpServletResponse response = mvc.perform(post(href).content(payload.toString()).contentType(mediaType)).//
|
||||
andExpect(status().isCreated()).//
|
||||
andExpect(header().string("Location", is(notNullValue()))).//
|
||||
andReturn().getResponse();
|
||||
|
||||
String content = response.getContentAsString();
|
||||
|
||||
if (StringUtils.hasText(content)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return client.request(response.getHeader("Location"));
|
||||
}
|
||||
|
||||
protected MockHttpServletResponse putAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
|
||||
|
||||
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
|
||||
|
||||
MockHttpServletResponse response = mvc.perform(put(href).content(payload.toString()).contentType(mediaType)).//
|
||||
andExpect(status().is2xxSuccessful()).//
|
||||
andReturn().getResponse();
|
||||
|
||||
return StringUtils.hasText(response.getContentAsString()) ? response : client.request(link);
|
||||
}
|
||||
|
||||
protected MockHttpServletResponse patchAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
|
||||
|
||||
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
|
||||
|
||||
MockHttpServletResponse response = mvc.perform(MockMvcRequestBuilders.request(HttpMethod.PATCH, href).//
|
||||
content(payload.toString()).contentType(mediaType)).//
|
||||
andExpect(status().is2xxSuccessful()).//
|
||||
andReturn().getResponse();
|
||||
|
||||
return StringUtils.hasText(response.getContentAsString()) ? response : client.request(href);
|
||||
}
|
||||
|
||||
protected void deleteAndVerify(Link link) throws Exception {
|
||||
|
||||
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
|
||||
|
||||
mvc.perform(delete(href)).//
|
||||
andExpect(status().isNoContent()).//
|
||||
andReturn().getResponse();
|
||||
|
||||
// Check that the resource is unavailable after a DELETE
|
||||
mvc.perform(get(href)).//
|
||||
andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
protected Link assertHasContentLinkWithRel(String rel, MockHttpServletResponse response) throws Exception {
|
||||
return assertContentLinkWithRel(rel, response, true);
|
||||
}
|
||||
|
||||
protected void assertDoesNotHaveContentLinkWithRel(String rel, MockHttpServletResponse response) throws Exception {
|
||||
assertContentLinkWithRel(rel, response, false);
|
||||
}
|
||||
|
||||
protected Link assertContentLinkWithRel(String rel, MockHttpServletResponse response, boolean expected)
|
||||
throws Exception {
|
||||
|
||||
String content = response.getContentAsString();
|
||||
|
||||
try {
|
||||
|
||||
String href = JsonPath.read(content, String.format(CONTENT_LINK_JSONPATH, rel)).toString();
|
||||
assertThat("Expected to find a link with rel" + rel + " in the content section of the response!", href,
|
||||
is(expected ? notNullValue() : nullValue()));
|
||||
|
||||
return new Link(href, rel);
|
||||
|
||||
} catch (InvalidPathException o_O) {
|
||||
|
||||
if (expected) {
|
||||
fail("Didn't find any content in the given response!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertDoesNotHaveLinkWithRel(String rel, MockHttpServletResponse response) throws Exception {
|
||||
|
||||
String content = response.getContentAsString();
|
||||
Link link = client.getDiscoverer(response).findLinkWithRel(rel, content);
|
||||
|
||||
assertThat("Expected not to find link with rel " + rel + " but found " + link + "!", link, is(nullValue()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T assertHasJsonPathValue(String path, MockHttpServletResponse response) throws Exception {
|
||||
|
||||
String content = response.getContentAsString();
|
||||
Object jsonPathResult = JsonPath.read(content, path);
|
||||
|
||||
assertThat(String.format("JSONPath lookup for %s did return null in %s.", path, content), jsonPathResult,
|
||||
is(notNullValue()));
|
||||
|
||||
if (jsonPathResult instanceof JSONArray) {
|
||||
JSONArray array = (JSONArray) jsonPathResult;
|
||||
assertThat(array, hasSize(greaterThan(0)));
|
||||
}
|
||||
|
||||
return (T) jsonPathResult;
|
||||
}
|
||||
|
||||
protected void assertJsonPathDoesntExist(String path, MockHttpServletResponse response) throws Exception {
|
||||
|
||||
try {
|
||||
|
||||
Object result = JsonPath.read(response.getContentAsString(), path);
|
||||
|
||||
if (result != null) {
|
||||
fail("Was expecting to find no value for path " + path + " but got " + result.toString());
|
||||
}
|
||||
|
||||
} catch (InvalidPathException e) {}
|
||||
}
|
||||
|
||||
protected String assertJsonPathEquals(String path, String expected, MockHttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
Object jsonQueryResults = assertHasJsonPathValue(path, response);
|
||||
|
||||
String jsonString = "";
|
||||
|
||||
if (jsonQueryResults instanceof JSONArray) {
|
||||
jsonString = ((JSONArray) jsonQueryResults).toJSONString();
|
||||
} else {
|
||||
jsonString = jsonQueryResults != null ? jsonQueryResults.toString() : null;
|
||||
}
|
||||
|
||||
assertThat(jsonString, is(expected));
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
protected ResultMatcher doesNotHaveLinkWithRel(final String rel) {
|
||||
|
||||
return new ResultMatcher() {
|
||||
|
||||
@Override
|
||||
public void match(MvcResult result) throws Exception {
|
||||
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String s = response.getContentAsString();
|
||||
|
||||
assertThat("Expected not to find link with rel " + rel + " but found one in " + s, //
|
||||
client.getDiscoverer(response).findLinkWithRel(rel, s), nullValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected Map<String, String> getPayloadToPost() throws Exception {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
protected MultiValueMap<String, String> getRootAndLinkedResources() {
|
||||
return new LinkedMultiValueMap<String, String>(0);
|
||||
}
|
||||
}
|
||||
@@ -28,33 +28,33 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
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.RestResource;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AssociationLinks}.
|
||||
* Unit tests for {@link Associations}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AssociationLinksUnitTests {
|
||||
|
||||
AssociationLinks links;
|
||||
Associations links;
|
||||
|
||||
ResourceMappings mappings;
|
||||
MongoMappingContext mappingContext;
|
||||
MongoPersistentEntity<?> entity;
|
||||
KeyValueMappingContext mappingContext;
|
||||
KeyValuePersistentEntity<?> entity;
|
||||
ResourceMetadata sampleResourceMetadata;
|
||||
|
||||
@Mock RepositoryRestConfiguration config;
|
||||
@@ -62,10 +62,10 @@ public class AssociationLinksUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mappingContext = new MongoMappingContext();
|
||||
this.mappingContext = new KeyValueMappingContext();
|
||||
this.entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
this.mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(mappingContext)));
|
||||
this.links = new AssociationLinks(mappings, config);
|
||||
this.links = new Associations(mappings, config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,12 +73,12 @@ public class AssociationLinksUnitTests {
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullMappings() {
|
||||
new AssociationLinks(null, mock(RepositoryRestConfiguration.class));
|
||||
new Associations(null, mock(RepositoryRestConfiguration.class));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullConfiguration() {
|
||||
new AssociationLinks(mappings, null);
|
||||
new Associations(mappings, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +103,7 @@ public class AssociationLinksUnitTests {
|
||||
@Test
|
||||
public void considersUnexportedPropertyUnlinkable() {
|
||||
|
||||
MongoPersistentProperty property = entity.getPersistentProperty("unexportedProperty");
|
||||
KeyValuePersistentProperty property = entity.getPersistentProperty("unexportedProperty");
|
||||
assertThat(links.isLinkableAssociation(property), is(false));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* This class contains a common test suite used to verify multiple data stores with the same domain space. When
|
||||
* verifying support of a new data store, it's good to start with extending this suite of tests. However, if the data
|
||||
* store doesn't map well onto this, then a good alternative would be write a new test suite using
|
||||
* {@link org.springframework.data.rest.webmvc.AbstractWebIntegrationTests AbstractWebIntegrationTests} as the test
|
||||
* harness.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public abstract class CommonWebTests extends AbstractWebIntegrationTests {
|
||||
|
||||
protected abstract Iterable<String> expectedRootLinkRels();
|
||||
|
||||
// Root test cases
|
||||
|
||||
@Test
|
||||
public void exposesRootResource() throws Exception {
|
||||
|
||||
ResultActions actions = mvc.perform(get("/").accept(TestMvcClient.DEFAULT_MEDIA_TYPE)).andExpect(status().isOk());
|
||||
|
||||
for (String rel : expectedRootLinkRels()) {
|
||||
actions.andExpect(client.hasLinkWithRel(rel));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-113
|
||||
* @see DATAREST-638
|
||||
*/
|
||||
@Test
|
||||
public void exposesSchemasForResourcesExposed() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
|
||||
for (String rel : expectedRootLinkRels()) {
|
||||
|
||||
Link link = client.assertHasLinkWithRel(rel, response);
|
||||
|
||||
// Resource
|
||||
client.follow(link).andExpect(status().is2xxSuccessful());
|
||||
|
||||
Link profileLink = client.discoverUnique(link, "profile");
|
||||
|
||||
// Default metadata
|
||||
client.follow(profileLink).andExpect(status().is2xxSuccessful());
|
||||
|
||||
// JSON Schema
|
||||
client.follow(profileLink, RestMediaTypes.SCHEMA_JSON).andExpect(status().is2xxSuccessful());
|
||||
|
||||
// ALPS
|
||||
client.follow(profileLink, RestMediaTypes.ALPS_JSON).andExpect(status().is2xxSuccessful());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-203
|
||||
*/
|
||||
@Test
|
||||
public void servesHalWhenRequested() throws Exception {
|
||||
|
||||
mvc.perform(get("/")). //
|
||||
andExpect(content().contentType(MediaTypes.HAL_JSON)). //
|
||||
andExpect(jsonPath("$._links", notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-203
|
||||
*/
|
||||
@Test
|
||||
public void servesHalWhenJsonIsRequested() throws Exception {
|
||||
|
||||
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON)). //
|
||||
andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)). //
|
||||
andExpect(jsonPath("$._links", notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-203
|
||||
*/
|
||||
@Test
|
||||
public void exposesSearchesForRootResources() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
|
||||
for (String rel : expectedRootLinkRels()) {
|
||||
|
||||
Link link = client.assertHasLinkWithRel(rel, response);
|
||||
String rootResourceRepresentation = client.request(link).getContentAsString();
|
||||
Link searchLink = client.getDiscoverer(response).findLinkWithRel("search", rootResourceRepresentation);
|
||||
|
||||
if (searchLink != null) {
|
||||
client.follow(searchLink).//
|
||||
andExpect(client.hasLinkWithRel("self")).//
|
||||
andExpect(jsonPath("$.domainType", is(nullValue()))); // DATAREST-549
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nic() throws Exception {
|
||||
|
||||
Map<String, String> payloads = getPayloadToPost();
|
||||
assumeFalse(payloads.isEmpty());
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
|
||||
for (String rel : expectedRootLinkRels()) {
|
||||
|
||||
String payload = payloads.get(rel);
|
||||
|
||||
if (payload != null) {
|
||||
|
||||
Link link = client.assertHasLinkWithRel(rel, response);
|
||||
String target = link.expand().getHref();
|
||||
|
||||
MockHttpServletRequestBuilder request = post(target).//
|
||||
content(payload).//
|
||||
contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
mvc.perform(request). //
|
||||
andExpect(status().isCreated());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-198
|
||||
*/
|
||||
@Test
|
||||
public void accessLinkedResources() throws Exception {
|
||||
|
||||
MockHttpServletResponse rootResource = client.request("/");
|
||||
|
||||
for (Map.Entry<String, List<String>> linked : getRootAndLinkedResources().entrySet()) {
|
||||
|
||||
Link resourceLink = client.assertHasLinkWithRel(linked.getKey(), rootResource);
|
||||
MockHttpServletResponse resource = client.request(resourceLink);
|
||||
|
||||
for (String linkedRel : linked.getValue()) {
|
||||
|
||||
// Find URIs pointing to linked resources
|
||||
String jsonPath = String.format("$..%s._links.%s.href", linked.getKey(), linkedRel);
|
||||
String representation = resource.getContentAsString();
|
||||
JSONArray uris = JsonPath.read(representation, jsonPath);
|
||||
|
||||
for (Object href : uris) {
|
||||
|
||||
client.follow(href.toString()). //
|
||||
andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-230
|
||||
*/
|
||||
@Test
|
||||
public void exposesDescriptionAsAlpsDocuments() throws Exception {
|
||||
|
||||
MediaType ALPS_MEDIA_TYPE = MediaType.valueOf("application/alps+json");
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
Link profileLink = client.assertHasLinkWithRel("profile", response);
|
||||
|
||||
mvc.perform(//
|
||||
get(profileLink.expand().getHref()).//
|
||||
accept(ALPS_MEDIA_TYPE))
|
||||
.//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(content().contentType(ALPS_MEDIA_TYPE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-448
|
||||
*/
|
||||
@Test
|
||||
public void returnsNotFoundForUriNotBackedByARepository() throws Exception {
|
||||
|
||||
mvc.perform(get("/index.html")).//
|
||||
andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-658
|
||||
*/
|
||||
@Test
|
||||
public void collectionResourcesExposeLinksAsHeadersForHeadRequest() throws Exception {
|
||||
|
||||
for (String rel : expectedRootLinkRels()) {
|
||||
|
||||
Link link = client.discoverUnique(rel);
|
||||
|
||||
MockHttpServletResponse response = mvc.perform(head(link.expand().getHref()))//
|
||||
.andExpect(status().isNoContent())//
|
||||
.andReturn().getResponse();
|
||||
|
||||
Links links = Links.valueOf(response.getHeader("Link"));
|
||||
|
||||
assertThat(links.hasLink(Link.REL_SELF), is(true));
|
||||
assertThat(links.hasLink("profile"), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-661
|
||||
*/
|
||||
@Test
|
||||
public void patchToNonExistingResourceReturnsNotFound() throws Exception {
|
||||
|
||||
String rel = expectedRootLinkRels().iterator().next();
|
||||
String uri = client.discoverUnique(rel).expand().getHref().concat("/");
|
||||
String id = "4711";
|
||||
Integer status = null;
|
||||
|
||||
do {
|
||||
|
||||
// Try to find non existing resource
|
||||
uri = uri.concat(id);
|
||||
status = mvc.perform(get(URI.create(uri))).andReturn().getResponse().getStatus();
|
||||
|
||||
} while (status != HttpStatus.NOT_FOUND.value());
|
||||
|
||||
// PATCH to non-existing resource
|
||||
mvc.perform(patch(URI.create(uri))).andExpect(status().isNotFound());
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.jpa.PersonRepository;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.LinkDiscoverers;
|
||||
import org.springframework.hateoas.core.JsonPathLinkDiscoverer;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Integration tests for DATAREST-363.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = { JpaRepositoryConfig.class, RepositoryRestMvcConfiguration.class,
|
||||
DuplicateLinkListingTests.Config.class })
|
||||
public class DuplicateLinkListingTests {
|
||||
|
||||
private static MediaType MEDIA_TYPE = MediaType.APPLICATION_JSON;
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
@Autowired LinkDiscoverers discoverers;
|
||||
@Autowired PersonRepository personRepository;
|
||||
|
||||
TestMvcClient testMvcClient;
|
||||
|
||||
@Configuration
|
||||
static class Config extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public LinkDiscoverer classicLinkDiscover() {
|
||||
return new JsonPathLinkDiscoverer("$.links[?(@.rel == '%s')].href", MEDIA_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
config.setDefaultMediaType(MEDIA_TYPE).useHalAsDefaultJsonMediaType(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).//
|
||||
defaultRequest(get("/")).build();
|
||||
testMvcClient = new TestMvcClient(mvc, discoverers);
|
||||
|
||||
personRepository.save(new Person("Frodo", "Baggins"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-363
|
||||
*/
|
||||
@Test
|
||||
public void testBasics() throws Exception {
|
||||
|
||||
ResultActions frodoActions = testMvcClient.follow("/people/1");
|
||||
|
||||
frodoActions.andExpect(jsonPath("$.links").value(hasSize(4)));
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.webmvc.AbstractControllerIntegrationTests.TestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.support.Projector;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link PersistentEntityResourceAssembler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = { TestConfiguration.class, MongoDbRepositoryConfig.class })
|
||||
public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired EntityLinks entityLinks;
|
||||
@Autowired @Qualifier("objectMapper") ObjectMapper objectMapper;
|
||||
@Autowired AssociationLinks associations;
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void addsSelfAndSingleResourceLinkToResourceByDefault() throws Exception {
|
||||
|
||||
Projector projector = mock(Projector.class);
|
||||
|
||||
when(projector.projectExcerpt(anyObject())).thenAnswer(new ReturnsArgumentAt(0));
|
||||
|
||||
PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, projector,
|
||||
associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.<EntityLookup<?>> emptyList()));
|
||||
|
||||
User user = new User();
|
||||
user.id = BigInteger.valueOf(4711);
|
||||
|
||||
PersistentEntityResource resource = assembler.toResource(user);
|
||||
|
||||
System.out.println(objectMapper.writeValueAsString(resource));
|
||||
Links links = new Links(resource.getLinks());
|
||||
|
||||
assertThat(links, is(Matchers.<Link> iterableWithSize(2)));
|
||||
assertThat(links.getLink("self").getVariables(), is(Matchers.empty()));
|
||||
assertThat(links.getLink("user").getVariableNames(), is(hasItem("projection")));
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverers;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Series of tests to verify {@link ProfileController} serves ALPS and JSON Schema metadata from the root level and
|
||||
* at collection resource levels.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @since 2.4
|
||||
*/
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = { JpaRepositoryConfig.class, ProfileIntegrationTests.Config.class})
|
||||
public class ProfileIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
@Autowired LinkDiscoverers discoverers;
|
||||
|
||||
private static final String ROOT_URI = "/api";
|
||||
|
||||
@Configuration
|
||||
static class Config extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
config.setBasePath(ROOT_URI);
|
||||
}
|
||||
}
|
||||
|
||||
TestMvcClient client;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
this.client = new TestMvcClient(mvc, this.discoverers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-230
|
||||
* @see DATAREST-638
|
||||
*/
|
||||
@Test
|
||||
public void exposesProfileLink() throws Exception {
|
||||
|
||||
client.follow(ROOT_URI)//
|
||||
.andExpect(status().is2xxSuccessful())//
|
||||
.andExpect(jsonPath("$._links.profile.href", endsWith(ProfileController.PROFILE_ROOT_MAPPING)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-230
|
||||
* @see DATAREST-638
|
||||
*/
|
||||
@Test
|
||||
public void profileRootLinkContainsMetadataForEachRepo() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique(new Link(ROOT_URI), ProfileResourceProcessor.PROFILE_REL);
|
||||
|
||||
assertThat(client.discoverUnique(profileLink, "self", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "people", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "items", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "authors", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "books", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "orders", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "receipts", MediaType.ALL), is(notNullValue()));
|
||||
assertThat(client.discoverUnique(profileLink, "addresses", MediaType.ALL), is(notNullValue()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see DATAREST-638
|
||||
*/
|
||||
@Test
|
||||
public void profileLinkOnCollectionResourceLeadsToRepositorySpecificMetadata() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique(new Link(ROOT_URI), "people");
|
||||
Link profileLink = client.discoverUnique(peopleLink, ProfileResourceProcessor.PROFILE_REL);
|
||||
|
||||
client.follow(profileLink, RestMediaTypes.ALPS_JSON)
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, RestMediaTypes.ALPS_JSON_VALUE));
|
||||
|
||||
client.follow(profileLink, RestMediaTypes.SCHEMA_JSON)
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, RestMediaTypes.SCHEMA_JSON_VALUE));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.rest.webmvc.TestMvcClient.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RepositoryController}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RepositoryControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired RepositoryController controller;
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void rootResourceExposesGetOnly() {
|
||||
|
||||
HttpEntity<?> response = controller.optionsForRepositories();
|
||||
assertAllowHeaders(response, HttpMethod.GET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333, DATAREST-330
|
||||
*/
|
||||
@Test
|
||||
public void headRequestReturnsNoContent() {
|
||||
assertThat(controller.headForRepositories().getStatusCode(), is(HttpStatus.NO_CONTENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-160, DATAREST-333, DATAREST-463
|
||||
*/
|
||||
@Test
|
||||
public void exposesLinksToRepositories() {
|
||||
|
||||
RepositoryLinksResource resource = controller.listRepositories().getBody();
|
||||
|
||||
assertThat(resource.getLinks(), hasSize(8));
|
||||
|
||||
assertThat(resource.hasLink("people"), is(true));
|
||||
assertThat(resource.hasLink("orders"), is(true));
|
||||
assertThat(resource.hasLink("addresses"), is(true));
|
||||
assertThat(resource.hasLink("books"), is(true));
|
||||
assertThat(resource.hasLink("authors"), is(true));
|
||||
assertThat(resource.hasLink("receipts"), is(true));
|
||||
assertThat(resource.hasLink("items"), is(true));
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.rest.webmvc.TestMvcClient.*;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.jpa.Address;
|
||||
import org.springframework.data.rest.webmvc.jpa.AddressRepository;
|
||||
import org.springframework.data.rest.webmvc.jpa.CreditCard;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.Order;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
|
||||
import org.springframework.data.rest.webmvc.support.ETag;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RepositoryEntityController}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jeremy Rickard
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RepositoryEntityControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired RepositoryEntityController controller;
|
||||
@Autowired AddressRepository repository;
|
||||
@Autowired RepositoryRestConfiguration configuration;
|
||||
@Autowired PersistentEntityResourceAssembler assembler;
|
||||
@Autowired PersistentEntities entities;
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test(expected = HttpRequestMethodNotSupportedException.class)
|
||||
public void returnsNotFoundForListingEntitiesIfFindAllNotExported() throws Exception {
|
||||
|
||||
repository.save(new Address());
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Address.class);
|
||||
controller.getCollectionResource(request, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test(expected = HttpRequestMethodNotSupportedException.class)
|
||||
public void rejectsEntityCreationIfSaveIsNotExported() throws Exception {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Address.class);
|
||||
|
||||
controller.postCollectionResource(request, null, null, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-301
|
||||
*/
|
||||
@Test
|
||||
public void setsExpandedSelfUriInLocationHeader() throws Exception {
|
||||
|
||||
RootResourceInformation information = getResourceInformation(Order.class);
|
||||
|
||||
PersistentEntityResource persistentEntityResource = PersistentEntityResource
|
||||
.build(new Order(new Person()), entities.getPersistentEntity(Order.class)).build();
|
||||
|
||||
ResponseEntity<?> entity = controller.putItemResource(information, persistentEntityResource, 1L, assembler,
|
||||
ETag.NO_ETAG, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
assertThat(entity.getHeaders().getLocation().toString(), not(Matchers.endsWith("{?projection}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test
|
||||
public void exposesHeadForCollectionResourceIfExported() throws Exception {
|
||||
ResponseEntity<?> entity = controller.headCollectionResource(getResourceInformation(Person.class),
|
||||
new DefaultedPageable(null, false));
|
||||
assertThat(entity.getStatusCode(), is(HttpStatus.NO_CONTENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeHeadForCollectionResourceIfNotExported() throws Exception {
|
||||
controller.headCollectionResource(getResourceInformation(CreditCard.class), new DefaultedPageable(null, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test
|
||||
public void exposesHeadForItemResourceIfExported() throws Exception {
|
||||
|
||||
Address address = repository.save(new Address());
|
||||
|
||||
ResponseEntity<?> entity = controller.headForItemResource(getResourceInformation(Address.class), address.id,
|
||||
assembler);
|
||||
|
||||
assertThat(entity.getStatusCode(), is(HttpStatus.NO_CONTENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeHeadForItemResourceIfNotExisting() throws Exception {
|
||||
controller.headForItemResource(getResourceInformation(CreditCard.class), 1L, assembler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void doesNotExposeMethodsForOptionsIfNotHttpMethodsSupportedForCollectionResource() {
|
||||
|
||||
HttpEntity<?> response = controller.optionsForCollectionResource(getResourceInformation(Address.class));
|
||||
assertAllowHeaders(response, OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void exposesSupportedHttpMethodsInAllowHeaderForOptionsRequestToCollectionResource() {
|
||||
|
||||
HttpEntity<?> response = controller.optionsForCollectionResource(getResourceInformation(Person.class));
|
||||
assertAllowHeaders(response, GET, POST, HEAD, OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void exposesSupportedHttpMethodsInAllowHeaderForOptionsRequestToItemResource() {
|
||||
|
||||
HttpEntity<?> response = controller.optionsForItemResource(getResourceInformation(Person.class));
|
||||
assertAllowHeaders(response, GET, PUT, PATCH, DELETE, HEAD, OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333, DATAREST-348
|
||||
*/
|
||||
@Test
|
||||
public void optionsForItermResourceSetsAllowPatchHeader() {
|
||||
|
||||
ResponseEntity<?> entity = controller.optionsForItemResource(getResourceInformation(Person.class));
|
||||
|
||||
List<String> value = entity.getHeaders().get("Accept-Patch");
|
||||
|
||||
assertThat(value, hasSize(3));
|
||||
assertThat(value,
|
||||
hasItems(//
|
||||
RestMediaTypes.JSON_PATCH_JSON.toString(), //
|
||||
RestMediaTypes.MERGE_PATCH_JSON.toString(), //
|
||||
MediaType.APPLICATION_JSON_VALUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-34
|
||||
*/
|
||||
@Test
|
||||
public void returnsBodyOnPutForUpdateIfAcceptHeaderPresentByDefault() throws Exception {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Order.class);
|
||||
Order order = request.getInvoker().invokeSave(new Order(new Person()));
|
||||
|
||||
PersistentEntityResource persistentEntityResource = PersistentEntityResource
|
||||
.build(new Order(new Person()), entities.getPersistentEntity(Order.class)).build();
|
||||
|
||||
assertThat(controller.putItemResource(request, persistentEntityResource, order.getId(), assembler, ETag.NO_ETAG,
|
||||
MediaType.APPLICATION_JSON_VALUE).hasBody(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-34
|
||||
*/
|
||||
@Test
|
||||
public void returnsBodyForCreatingPutIfAcceptHeaderPresentByDefault() throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Order.class);
|
||||
PersistentEntityResource persistentEntityResource = PersistentEntityResource
|
||||
.build(new Order(new Person()), entities.getPersistentEntity(Order.class)).build();
|
||||
|
||||
assertThat(controller.putItemResource(request, persistentEntityResource, 1L, assembler, ETag.NO_ETAG,
|
||||
MediaType.APPLICATION_JSON_VALUE).hasBody(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-34
|
||||
*/
|
||||
@Test
|
||||
public void returnsBodyForPostIfAcceptHeaderIsPresentByDefault() throws Exception {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Order.class);
|
||||
PersistentEntityResource persistentEntityResource = PersistentEntityResource
|
||||
.build(new Order(new Person()), entities.getPersistentEntity(Order.class)).build();
|
||||
|
||||
assertThat(controller
|
||||
.postCollectionResource(request, persistentEntityResource, assembler, MediaType.APPLICATION_JSON_VALUE)
|
||||
.hasBody(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-34
|
||||
*/
|
||||
@Test
|
||||
public void doesNotReturnBodyForPostIfNoAcceptHeaderPresentByDefault() throws Exception {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Order.class);
|
||||
PersistentEntityResource persistentEntityResource = PersistentEntityResource
|
||||
.build(new Order(new Person()), entities.getPersistentEntity(Order.class)).build();
|
||||
|
||||
assertThat(controller.postCollectionResource(request, persistentEntityResource, assembler, null).hasBody(),
|
||||
is(false));
|
||||
assertThat(controller.postCollectionResource(request, persistentEntityResource, assembler, "").hasBody(),
|
||||
is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-581
|
||||
*/
|
||||
@Test
|
||||
public void createsEtagForProjectedEntityCorrectly() throws Exception {
|
||||
|
||||
Address address = repository.save(new Address());
|
||||
|
||||
PersistentEntityResourceAssembler assembler = Mockito.mock(PersistentEntityResourceAssembler.class);
|
||||
AddressProjection addressProjection = new SpelAwareProxyProjectionFactory()
|
||||
.createProjection(AddressProjection.class);
|
||||
|
||||
PersistentEntityResource resource = PersistentEntityResource
|
||||
.build(addressProjection, entities.getPersistentEntity(Address.class)).build();
|
||||
|
||||
Mockito.when(assembler.toFullResource(Mockito.any(Object.class))).thenReturn(resource);
|
||||
|
||||
ResponseEntity<Resource<?>> entity = controller.getItemResource(getResourceInformation(Address.class), address.id,
|
||||
assembler, new LinkedMultiValueMap<String, String>());
|
||||
|
||||
assertThat(entity.getHeaders().getETag(), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test
|
||||
public void deletesEntityWithCustomLookupCorrectly() throws Exception {
|
||||
|
||||
Address address = repository.save(new Address());
|
||||
assertThat(repository.findOne(address.id), is(notNullValue()));
|
||||
|
||||
RootResourceInformation resourceInformation = getResourceInformation(Address.class);
|
||||
RepositoryInvoker invoker = spy(resourceInformation.getInvoker());
|
||||
doReturn(address).when(invoker).invokeFindOne("foo");
|
||||
|
||||
RootResourceInformation informationSpy = Mockito.spy(resourceInformation);
|
||||
doReturn(invoker).when(informationSpy).getInvoker();
|
||||
|
||||
controller.deleteItemResource(informationSpy, "foo", ETag.from("0"));
|
||||
|
||||
assertThat(repository.findOne(address.id), is(nullValue()));
|
||||
}
|
||||
|
||||
interface AddressProjection {}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.jpa.Book;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.TestDataPopulator;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RepositoryPropertyReferenceControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired RepositoryPropertyReferenceController controller;
|
||||
@Autowired TestDataPopulator populator;
|
||||
|
||||
PersistentEntityResourceAssembler assembler;
|
||||
RootResourceInformation information;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.assembler = mock(PersistentEntityResourceAssembler.class);
|
||||
this.information = getResourceInformation(Book.class);
|
||||
this.populator.populateRepositories();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposesResourceForCustomizedPropertyResourcePath() throws Exception {
|
||||
assertThat(controller.followPropertyReference(information, 1L, "creators", assembler).getStatusCode(),
|
||||
is(HttpStatus.OK));
|
||||
}
|
||||
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeOriginalPathIfPropertyResourcePathIsCustomized() throws Exception {
|
||||
controller.followPropertyReference(information, 1L, "authors", assembler);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link BasePathAwareHandlerMapping}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Elephants Crossing - Echo (Irrelephant)
|
||||
*/
|
||||
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
|
||||
public class RepositoryRestHandlerMappingIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired DelegatingHandlerMapping mapping;
|
||||
|
||||
/**
|
||||
* @see DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void usesMethodsWithoutProducesClauseForGeneralJsonRequests() throws Exception {
|
||||
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest("GET", "/users");
|
||||
mockRequest.addHeader("Accept", "application/*+json");
|
||||
|
||||
HandlerExecutionChain chain = mapping.getHandler(mockRequest);
|
||||
|
||||
assertThat(chain, is(notNullValue()));
|
||||
|
||||
Object handler = chain.getHandler();
|
||||
assertThat(handler, is(instanceOf(HandlerMethod.class)));
|
||||
|
||||
HandlerMethod method = (HandlerMethod) handler;
|
||||
assertThat(method.getMethod().getDeclaringClass(), is(typeCompatibleWith(RepositoryEntityController.class)));
|
||||
assertThat(method.getMethod().getName(), is("getCollectionResource"));
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.gemfire.GemfireRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Configuration
|
||||
@Import({ JpaRepositoryConfig.class, MongoDbRepositoryConfig.class, GemfireRepositoryConfig.class })
|
||||
public class RepositoryRestMvcTestConfig extends RepositoryRestMvcConfiguration {}
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.rest.webmvc.TestMvcClient.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.ResourceTester.HasSelfLink;
|
||||
import org.springframework.data.rest.webmvc.jpa.Address;
|
||||
import org.springframework.data.rest.webmvc.jpa.Author;
|
||||
import org.springframework.data.rest.webmvc.jpa.Book;
|
||||
import org.springframework.data.rest.webmvc.jpa.CreditCard;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.jpa.TestDataPopulator;
|
||||
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Integration tests for the {@link RepositorySearchController}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RepositorySearchControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
static final DefaultedPageable PAGEABLE = new DefaultedPageable(new PageRequest(0, 10), true);
|
||||
|
||||
@Autowired TestDataPopulator loader;
|
||||
@Autowired RepositorySearchController controller;
|
||||
@Autowired PersistentEntityResourceAssembler assembler;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
loader.populateRepositories();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rendersCorrectSearchLinksForPersons() throws Exception {
|
||||
|
||||
RootResourceInformation request = getResourceInformation(Person.class);
|
||||
ResourceSupport resource = controller.listSearches(request);
|
||||
|
||||
ResourceTester tester = ResourceTester.of(resource);
|
||||
tester.assertNumberOfLinks(6); // Self link included
|
||||
tester.assertHasLinkEndingWith("findFirstPersonByFirstName", "findFirstPersonByFirstName{?firstname,projection}");
|
||||
tester.assertHasLinkEndingWith("firstname", "firstname{?firstname,page,size,sort,projection}");
|
||||
tester.assertHasLinkEndingWith("lastname", "lastname{?lastname,sort,projection}");
|
||||
tester.assertHasLinkEndingWith("findByCreatedUsingISO8601Date",
|
||||
"findByCreatedUsingISO8601Date{?date,page,size,sort,projection}");
|
||||
tester.assertHasLinkEndingWith("findByCreatedGreaterThan",
|
||||
"findByCreatedGreaterThan{?date,page,size,sort,projection}");
|
||||
}
|
||||
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void returns404ForUnexportedRepository() {
|
||||
controller.listSearches(getResourceInformation(CreditCard.class));
|
||||
}
|
||||
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void returns404ForRepositoryWithoutSearches() {
|
||||
controller.listSearches(getResourceInformation(Author.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executesSearchAgainstRepository() {
|
||||
|
||||
RootResourceInformation resourceInformation = getResourceInformation(Person.class);
|
||||
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>(1);
|
||||
parameters.add("firstname", "John");
|
||||
|
||||
ResponseEntity<Object> response = controller.executeSearch(resourceInformation, parameters, "firstname", PAGEABLE,
|
||||
null, assembler);
|
||||
|
||||
ResourceTester tester = ResourceTester.of(response.getBody());
|
||||
PagedResources<Object> pagedResources = tester.assertIsPage();
|
||||
assertThat(pagedResources.getContent().size(), is(1));
|
||||
|
||||
ResourceMetadata metadata = getMetadata(Person.class);
|
||||
tester.withContentResource(new HasSelfLink(BASE.slash(metadata.getPath()).slash("{id}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeHeadForSearchResourceIfResourceDoesnHaveSearches() {
|
||||
controller.headForSearches(getResourceInformation(Author.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void exposesHeadForSearchResourceIfResourceIsNotExposed() {
|
||||
controller.headForSearches(getResourceInformation(CreditCard.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test
|
||||
public void exposesHeadForSearchResourceIfResourceIsExposed() {
|
||||
controller.headForSearches(getResourceInformation(Person.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test
|
||||
public void exposesHeadForExistingQueryMethodResource() {
|
||||
controller.headForSearch(getResourceInformation(Person.class), "findByCreatedUsingISO8601Date");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-330
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeHeadForInvalidQueryMethodResource() {
|
||||
controller.headForSearch(getResourceInformation(Person.class), "foobar");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void searchResourceSupportsGetOnly() {
|
||||
assertAllowHeaders(controller.optionsForSearches(getResourceInformation(Person.class)), HttpMethod.GET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void returns404ForOptionsForRepositoryWithoutSearches() {
|
||||
controller.optionsForSearches(getResourceInformation(Address.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-333
|
||||
*/
|
||||
@Test
|
||||
public void queryMethodResourceSupportsGetOnly() {
|
||||
|
||||
RootResourceInformation resourceInformation = getResourceInformation(Person.class);
|
||||
HttpEntity<Object> response = controller.optionsForSearch(resourceInformation, "firstname");
|
||||
|
||||
assertAllowHeaders(response, HttpMethod.GET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-502
|
||||
*/
|
||||
@Test
|
||||
public void interpretsUriAsReferenceToRelatedEntity() {
|
||||
|
||||
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>(1);
|
||||
parameters.add("author", "/author/1");
|
||||
|
||||
RootResourceInformation resourceInformation = getResourceInformation(Book.class);
|
||||
|
||||
ResponseEntity<Object> result = controller.executeSearch(resourceInformation, parameters, "findByAuthorsContains",
|
||||
PAGEABLE, null, assembler);
|
||||
|
||||
assertThat(result.getBody(), is(instanceOf(Resources.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-515
|
||||
*/
|
||||
@Test
|
||||
public void repositorySearchResourceExposesDomainType() {
|
||||
|
||||
RepositorySearchesResource searches = controller.listSearches(getResourceInformation(Person.class));
|
||||
|
||||
assertThat(searches.getDomainType(), is(typeCompatibleWith(Person.class)));
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RequestParameters {
|
||||
|
||||
public static RequestParameters NONE = new RequestParameters();
|
||||
|
||||
private final Map<String, String[]> parameters;
|
||||
|
||||
public RequestParameters(String key, String... values) {
|
||||
this(new HashMap<String, String[]>(), key, values);
|
||||
}
|
||||
|
||||
private RequestParameters(Map<String, String[]> parameters, String key, String... values) {
|
||||
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
Assert.hasText(key, "Key must not be null or empty!");
|
||||
|
||||
this.parameters = new HashMap<String, String[]>(parameters);
|
||||
this.parameters.put(key, values);
|
||||
}
|
||||
|
||||
private RequestParameters() {
|
||||
this.parameters = new HashMap<String, String[]>();
|
||||
}
|
||||
|
||||
public RequestParameters and(String key, String... values) {
|
||||
return new RequestParameters(parameters, key, values);
|
||||
}
|
||||
|
||||
public Map<String, String[]> asMap() {
|
||||
return Collections.unmodifiableMap(parameters);
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
/**
|
||||
* Simple wrapper for {@link Resource}s to allow easy assertions on it.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceTester {
|
||||
|
||||
private final ResourceSupport resource;
|
||||
|
||||
public static ResourceTester of(Object object) {
|
||||
assertThat(object, is(instanceOf(ResourceSupport.class)));
|
||||
return new ResourceTester((ResourceSupport) object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResourceTester} for the given {@link ResourceSupport}.
|
||||
*
|
||||
* @param resource must not be {@literal null}.
|
||||
*/
|
||||
private ResourceTester(ResourceSupport resource) {
|
||||
Assert.notNull(resource, "Resource must not be null!");
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the {@link Resource} contains the given number of {@link Link}s.
|
||||
*
|
||||
* @param number
|
||||
*/
|
||||
public void assertNumberOfLinks(int number) {
|
||||
assertThat(resource.getLinks().size(), is(number));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the {@link Resource} has a link with the given rel and href.
|
||||
*
|
||||
* @param rel must not be {@literal null}.
|
||||
* @param href can be {@literal null}, if so, only the presence of a {@link Link} with the given rel is checked.
|
||||
*/
|
||||
public Link assertHasLink(String rel, String href) {
|
||||
return assertHasLinkMatching(rel, href == null ? null : is(href));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the {@link Resource} has a link with the given rel and ending with the given href.
|
||||
*
|
||||
* @param rel must not be {@literal null}.
|
||||
* @param href can be {@literal null}, if so, only the presence of a {@link Link} with the given rel is checked.
|
||||
*/
|
||||
public Link assertHasLinkEndingWith(String rel, String hrefEnd) {
|
||||
return assertHasLinkMatching(rel, hrefEnd == null ? null : endsWith(hrefEnd));
|
||||
}
|
||||
|
||||
private final Link assertHasLinkMatching(String rel, Matcher<String> hrefMatcher) {
|
||||
|
||||
Link link = resource.getLink(rel);
|
||||
assertThat("Expected link with rel '" + rel + "' but didn't find it in " + resource.getLinks(), link,
|
||||
is(notNullValue()));
|
||||
|
||||
if (hrefMatcher != null) {
|
||||
assertThat(link.getHref(), is(hrefMatcher));
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> PagedResources<T> assertIsPage() {
|
||||
|
||||
assertThat(resource, is(instanceOf(PagedResources.class)));
|
||||
return (PagedResources<T>) resource;
|
||||
}
|
||||
|
||||
public ResourceTester getContentResource() {
|
||||
|
||||
assertThat(resource, is(instanceOf(Resources.class)));
|
||||
Object next = ((Resources<?>) resource).getContent().iterator().next();
|
||||
|
||||
assertThat(next, is(instanceOf(ResourceSupport.class)));
|
||||
return new ResourceTester((ResourceSupport) next);
|
||||
}
|
||||
|
||||
public void withContentResource(ContentResourceHandler handler) {
|
||||
|
||||
assertThat(resource, is(instanceOf(Resources.class)));
|
||||
|
||||
for (Object element : ((Resources<?>) resource).getContent()) {
|
||||
assertThat(element, is(instanceOf(ResourceSupport.class)));
|
||||
handler.doWith(of(element));
|
||||
}
|
||||
}
|
||||
|
||||
public interface ContentResourceHandler {
|
||||
|
||||
void doWith(ResourceTester content);
|
||||
}
|
||||
|
||||
public static class HasSelfLink implements ContentResourceHandler {
|
||||
|
||||
private final Path template;
|
||||
|
||||
public HasSelfLink(Path template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceTester.ContentResourceHandler#doWith(org.springframework.data.rest.webmvc.ResourceTester)
|
||||
*/
|
||||
@Override
|
||||
public void doWith(ResourceTester content) {
|
||||
|
||||
String href = content.assertHasLink("self", null).getHref();
|
||||
|
||||
UriTemplate uriTemplate = new UriTemplate(template.toString());
|
||||
assertThat(String.format("Expected %s to match %s!", href, uriTemplate.toString()), uriTemplate.matches(href),
|
||||
is(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-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.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.rest.core.mapping.ResourceType.*;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.data.rest.core.mapping.SupportedHttpMethods;
|
||||
import org.springframework.data.rest.webmvc.jpa.Address;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RootResourceInformation}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RootResourceInformationIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test
|
||||
public void getIsNotSupportedIfFindAllIsNotExported() {
|
||||
|
||||
SupportedHttpMethods supportedMethods = getResourceInformation(Address.class).getSupportedMethods();
|
||||
assertThat(supportedMethods.getMethodsFor(COLLECTION), not(hasItem(GET)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test
|
||||
public void postIsNotSupportedIfSaveIsNotExported() {
|
||||
|
||||
SupportedHttpMethods supportedMethods = getResourceInformation(Address.class).getSupportedMethods();
|
||||
assertThat(supportedMethods.getMethodsFor(COLLECTION), not(hasItem(POST)));
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.LinkDiscoverers;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* Helper methods for web integration testing.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class TestMvcClient {
|
||||
|
||||
public static MediaType DEFAULT_MEDIA_TYPE = org.springframework.hateoas.MediaTypes.HAL_JSON;
|
||||
|
||||
private final MockMvc mvc;
|
||||
private final LinkDiscoverers discoverers;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TestMvcClient} for the given {@link MockMvc} and {@link LinkDiscoverers}.
|
||||
*
|
||||
* @param mvc must not be {@literal null}.
|
||||
* @param discoverers must not be {@literal null}.
|
||||
*/
|
||||
public TestMvcClient(MockMvc mvc, LinkDiscoverers discoverers) {
|
||||
|
||||
Assert.notNull(mvc, "MockMvc must not be null!");
|
||||
Assert.notNull(discoverers, "LinkDiscoverers must not be null!");
|
||||
|
||||
this.mvc = mvc;
|
||||
this.discoverers = discoverers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes web tests. Will register a {@link MockHttpServletRequest} for the current thread.
|
||||
*/
|
||||
public static void initWebTest() {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
|
||||
RequestContextHolder.setRequestAttributes(requestAttributes);
|
||||
}
|
||||
|
||||
public static void assertAllowHeaders(HttpEntity<?> response, HttpMethod... methods) {
|
||||
|
||||
HttpHeaders headers = response.getHeaders();
|
||||
|
||||
assertThat(headers.getAllow(), hasSize(methods.length));
|
||||
assertThat(headers.getAllow(), hasItems(methods));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform GET [href] with an explicit Accept media type using MockMvc. Verify the requests succeeded and also came
|
||||
* back as the Accept type.
|
||||
*
|
||||
* @param href
|
||||
* @param contentType
|
||||
* @return a mocked servlet response with results from GET [href]
|
||||
* @throws Exception
|
||||
*/
|
||||
public MockHttpServletResponse request(String href, MediaType contentType) throws Exception {
|
||||
return mvc.perform(get(href).accept(contentType)). //
|
||||
andExpect(status().isOk()). //
|
||||
andExpect(content().contentType(contentType)). //
|
||||
andReturn().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform GET [href] with an explicit Accept media type using MockMvc. Verify the requests succeeded and also came
|
||||
* back as the Accept type.
|
||||
*
|
||||
* @param href
|
||||
* @param contentType
|
||||
* @return a mocked servlet response with results from GET [href]
|
||||
* @throws Exception
|
||||
*/
|
||||
public MockHttpServletResponse request(String href, MediaType contentType, HttpHeaders httpHeaders) throws Exception {
|
||||
return mvc.perform(get(href).accept(contentType).headers(httpHeaders)). //
|
||||
andExpect(status().isOk()). //
|
||||
andExpect(content().contentType(contentType)). //
|
||||
andReturn().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper that first expands the link using URI substitution before requesting with the default media
|
||||
* type.
|
||||
*
|
||||
* @param link
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public MockHttpServletResponse request(Link link) throws Exception {
|
||||
return request(link.expand().getHref());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper that first expands the link using URI substitution and then GET [href] using an explicit media
|
||||
* type
|
||||
*
|
||||
* @param link
|
||||
* @param mediaType
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public MockHttpServletResponse request(Link link, MediaType mediaType) throws Exception {
|
||||
return request(link.expand().getHref(), mediaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper to GET [href] using the default media type.
|
||||
*
|
||||
* @param href
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public MockHttpServletResponse request(String href) throws Exception {
|
||||
return request(href, DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given link, expand the href using URI substitution and then do a simple GET.
|
||||
*
|
||||
* @param link
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ResultActions follow(Link link) throws Exception {
|
||||
return follow(link.expand().getHref());
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow URL supplied as a string. NOTE: Assumes no URI templates.
|
||||
*
|
||||
* @param href
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ResultActions follow(String href) throws Exception {
|
||||
return follow(href, MediaType.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Folow Link with a specific Accept header (media type).
|
||||
*
|
||||
* @param link
|
||||
* @param accept
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ResultActions follow(Link link, MediaType accept) throws Exception {
|
||||
return follow(link.expand().getHref(), accept);
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow URL supplied as a string with a specific Accept header.
|
||||
* @param href
|
||||
* @param accept
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ResultActions follow(String href, MediaType accept) throws Exception {
|
||||
return mvc.perform(get(href).header(HttpHeaders.ACCEPT, accept.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover list of URIs associated with a rel, starting at the root node ("/")
|
||||
*
|
||||
* @param rel
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<Link> discover(String rel) throws Exception {
|
||||
return discover(new Link("/"), rel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover single URI associated with a rel, starting at the root node ("/")
|
||||
*
|
||||
* @param rel
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Link discoverUnique(String rel) throws Exception {
|
||||
|
||||
List<Link> discover = discover(rel);
|
||||
assertThat(discover, hasSize(1));
|
||||
return discover.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the given link relations from the root.
|
||||
*
|
||||
* @param rels
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Link discoverUnique(String... rels) throws Exception {
|
||||
|
||||
Iterator<String> toTraverse = Arrays.asList(rels).iterator();
|
||||
Link lastLink = null;
|
||||
|
||||
while (toTraverse.hasNext()) {
|
||||
|
||||
String rel = toTraverse.next();
|
||||
lastLink = lastLink == null ? discoverUnique(rel) : discoverUnique(lastLink, rel);
|
||||
}
|
||||
|
||||
return lastLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URI (root), discover the URIs for a given rel.
|
||||
*
|
||||
* @param root - URI to start from
|
||||
* @param rel - name of the relationship to seek links
|
||||
* @return list of {@link org.springframework.hateoas.Link Link} objects associated with the rel
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<Link> discover(Link root, String rel) throws Exception {
|
||||
|
||||
MockHttpServletResponse response = mvc.perform(get(root.expand().getHref()).accept(DEFAULT_MEDIA_TYPE)).//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(hasLinkWithRel(rel)).//
|
||||
andReturn().getResponse();
|
||||
|
||||
String s = response.getContentAsString();
|
||||
return getDiscoverer(response).findLinksWithRel(rel, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URI (root), discover the unique URI for a given rel. NOTE: Assumes there is only one URI
|
||||
*
|
||||
* @param root
|
||||
* @param rel
|
||||
* @return {@link org.springframework.hateoas.Link Link} tied to a given rel
|
||||
* @throws Exception
|
||||
*/
|
||||
public Link discoverUnique(Link root, String rel) throws Exception {
|
||||
return discoverUnique(root, rel, DEFAULT_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URI (root), discover the unique URI for a given rel. NOTE: Assumes there is only one URI
|
||||
*
|
||||
* @param root the link to the resource to access.
|
||||
* @param rel the link relation to discover in the response.
|
||||
* @param mediaType the {@link MediaType} to request.
|
||||
* @return {@link org.springframework.hateoas.Link Link} tied to a given rel
|
||||
* @throws Exception
|
||||
*/
|
||||
public Link discoverUnique(Link root, String rel, MediaType mediaType) throws Exception {
|
||||
|
||||
MockHttpServletResponse response = mvc
|
||||
.perform(get(root.expand().getHref())//
|
||||
.accept(mediaType))
|
||||
.andExpect(status().isOk())//
|
||||
.andExpect(hasLinkWithRel(rel))//
|
||||
.andReturn().getResponse();
|
||||
|
||||
return assertHasLinkWithRel(rel, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given servlet response, verify that the provided rel exists in its hypermedia. If so, return the URI link.
|
||||
*
|
||||
* @param rel
|
||||
* @param response
|
||||
* @return {@link org.springframework.hateoas.Link} of the rel found in the response
|
||||
* @throws Exception
|
||||
*/
|
||||
public Link assertHasLinkWithRel(String rel, MockHttpServletResponse response) throws Exception {
|
||||
|
||||
String content = response.getContentAsString();
|
||||
Link link = getDiscoverer(response).findLinkWithRel(rel, content);
|
||||
|
||||
assertThat("Expected to find link with rel " + rel + " but found none in " + content + "!", link,
|
||||
is(notNullValue()));
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockMvc matcher used to verify existence of rel with URI link
|
||||
*
|
||||
* @param rel
|
||||
* @return
|
||||
*/
|
||||
public ResultMatcher hasLinkWithRel(final String rel) {
|
||||
|
||||
return new ResultMatcher() {
|
||||
|
||||
@Override
|
||||
public void match(MvcResult result) throws Exception {
|
||||
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String s = response.getContentAsString();
|
||||
|
||||
assertThat("Expected to find link with rel " + rel + " but found none in " + s, //
|
||||
getDiscoverer(response).findLinkWithRel(rel, s), notNullValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the servlet response's content type, find the corresponding link discoverer.
|
||||
*
|
||||
* @param response
|
||||
* @return {@link org.springframework.hateoas.LinkDiscoverer}
|
||||
*/
|
||||
public LinkDiscoverer getDiscoverer(MockHttpServletResponse response) {
|
||||
|
||||
String contentType = response.getContentType();
|
||||
LinkDiscoverer linkDiscovererFor = discoverers.getLinkDiscovererFor(contentType);
|
||||
|
||||
assertThat("Did not find a LinkDiscoverer for returned media type " + contentType + "!", linkDiscovererFor,
|
||||
is(notNullValue()));
|
||||
|
||||
return linkDiscovererFor;
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.alps;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.AbstractControllerIntegrationTests;
|
||||
import org.springframework.data.rest.webmvc.ProfileController;
|
||||
import org.springframework.data.rest.webmvc.RestMediaTypes;
|
||||
import org.springframework.data.rest.webmvc.TestMvcClient;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
|
||||
import org.springframework.data.rest.webmvc.jpa.Item;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.LinkDiscoverers;
|
||||
import org.springframework.hateoas.core.JsonPathLinkDiscoverer;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link AlpsController}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = { JpaRepositoryConfig.class, AlpsControllerIntegrationTests.Config.class })
|
||||
public class AlpsControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
@Autowired LinkDiscoverers discoverers;
|
||||
@Autowired RepositoryRestConfiguration configuration;
|
||||
|
||||
@Configuration
|
||||
static class Config extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public LinkDiscoverer alpsLinkDiscoverer() {
|
||||
return new JsonPathLinkDiscoverer("$.descriptors[?(@.name == '%s')].href",
|
||||
MediaType.valueOf("application/alps+json"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
config.exposeIdsFor(Item.class);
|
||||
}
|
||||
}
|
||||
|
||||
TestMvcClient client;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
this.client = new TestMvcClient(mvc, this.discoverers);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
configuration.setEnableEnumTranslation(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-230
|
||||
*/
|
||||
@Test
|
||||
public void exposesAlpsCollectionResources() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link peopleLink = client.discoverUnique(profileLink, "people", MediaType.ALL);
|
||||
|
||||
client.follow(peopleLink, RestMediaTypes.ALPS_JSON)//
|
||||
.andExpect(jsonPath("$.alps.version").value("1.0"))//
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].name", hasItems("people", "person")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-638
|
||||
*/
|
||||
@Test
|
||||
public void verifyThatAlpsIsDefaultProfileFormat() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link peopleLink = client.discoverUnique(profileLink, "people", MediaType.ALL);
|
||||
|
||||
client.follow(peopleLink)//
|
||||
.andExpect(jsonPath("$.alps.version").value("1.0"))//
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].name", hasItems("people", "person")));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-463
|
||||
*/
|
||||
@Test
|
||||
public void verifyThatAttributesIgnoredDontAppearInAlps() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link itemsLink = client.discoverUnique(profileLink, "items", MediaType.ALL);
|
||||
|
||||
client.follow(itemsLink, RestMediaTypes.ALPS_JSON)//
|
||||
// Exposes standard property
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].descriptors[*].name", hasItems("name")))
|
||||
// Does not expose explicitly @JsonIgnored property
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].descriptors[*].name", not(hasItems("owner"))))
|
||||
// Does not expose properties pointing to non exposed types
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].descriptors[*].name", not(hasItems("manager", "curator"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-494
|
||||
*/
|
||||
@Test
|
||||
public void linksToJsonSchemaFromRepresentationDescriptor() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link itemsLink = client.discoverUnique(profileLink, "items", MediaType.ALL);
|
||||
|
||||
assertThat(itemsLink, is(notNullValue()));
|
||||
|
||||
client.follow(itemsLink, RestMediaTypes.ALPS_JSON)//
|
||||
.andExpect(
|
||||
jsonPath("$.alps.descriptors[?(@.id == 'item-representation')][0].href", endsWith("/profile/items")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-516
|
||||
*/
|
||||
@Test
|
||||
public void referenceToAssociatedEntityDesciptorPointsToRepresentationDescriptor() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link usersLink = client.discoverUnique(profileLink, "people", MediaType.ALL);
|
||||
|
||||
String jsonPath = "$.alps."; // Root
|
||||
jsonPath += "descriptors[?(@.id == 'person-representation')]."; // Representation descriptor
|
||||
jsonPath += "descriptors[?(@.name == 'father')][0]."; // First father descriptor
|
||||
jsonPath += "rt"; // Return type
|
||||
|
||||
client.follow(usersLink, RestMediaTypes.ALPS_JSON)//
|
||||
.andExpect(jsonPath(jsonPath,
|
||||
allOf(containsString(ProfileController.PROFILE_ROOT_MAPPING), endsWith("-representation"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-630
|
||||
*/
|
||||
@Test
|
||||
public void onlyExposesIdAttributesWhenExposedInTheConfiguration() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link itemsLink = client.discoverUnique(profileLink, "items", MediaType.ALL);
|
||||
|
||||
client.follow(itemsLink, RestMediaTypes.ALPS_JSON)//
|
||||
// Exposes identifier if configured to
|
||||
.andExpect(jsonPath("$.alps.descriptors[*].descriptors[*].name", hasItems("id", "name")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-683
|
||||
*/
|
||||
@Test
|
||||
public void enumValueListingsAreTranslatedIfEnabled() throws Exception {
|
||||
|
||||
configuration.setEnableEnumTranslation(true);
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link peopleLink = client.discoverUnique(profileLink, "people", MediaType.ALL);
|
||||
|
||||
client.follow(peopleLink)//
|
||||
.andExpect(jsonPath(
|
||||
"$.alps.descriptors[?(@.id == 'person-representation')].descriptors[?(@.name == 'gender')][0].doc.value",
|
||||
is("Male, Female, Undefined")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-753
|
||||
*/
|
||||
@Test
|
||||
public void alpsCanHandleGroovyDomainObjects() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profile");
|
||||
Link groovyDomainObjectLink = client.discoverUnique(profileLink, "simulatedGroovyDomainClasses");
|
||||
|
||||
client.follow(groovyDomainObjectLink)//
|
||||
.andExpect(jsonPath(
|
||||
"$.alps.descriptors[?(@.id == 'simulatedGroovyDomainClass-representation')][0].descriptors[0].name",
|
||||
is("name")));
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.config;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Base class for integration tests that are run against a particular configuration defined by the subclass.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
public abstract class AbstractRepositoryRestMvcConfigurationIntegrationTests {
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
protected MockMvc mvc;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.rest.webmvc.util.TestUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.webmvc.RestMediaTypes;
|
||||
import org.springframework.data.rest.webmvc.json.DomainObjectReader;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Address;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JsonPatchHandler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JsonPatchHandlerUnitTests {
|
||||
|
||||
JsonPatchHandler handler;
|
||||
User user;
|
||||
|
||||
@Mock ResourceMappings mappings;
|
||||
public @Rule ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
context.getPersistentEntity(User.class);
|
||||
|
||||
PersistentEntities entities = new PersistentEntities(Arrays.asList(context));
|
||||
|
||||
AssociationLinks associations = new AssociationLinks(mappings, mock(RepositoryRestConfiguration.class));
|
||||
|
||||
this.handler = new JsonPatchHandler(new ObjectMapper(), new DomainObjectReader(entities, associations));
|
||||
|
||||
Address address = new Address();
|
||||
address.street = "Foo";
|
||||
address.zipCode = "Bar";
|
||||
|
||||
this.user = new User();
|
||||
this.user.firstname = "Oliver";
|
||||
this.user.lastname = "Gierke";
|
||||
this.user.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-348
|
||||
*/
|
||||
@Test
|
||||
public void appliesRemoveOperationCorrectly() throws Exception {
|
||||
|
||||
String input = "[{ \"op\": \"replace\", \"path\": \"/address/zipCode\", \"value\": \"ZIP\" },"
|
||||
+ "{ \"op\": \"remove\", \"path\": \"/lastname\" }]";
|
||||
|
||||
User result = handler.applyPatch(asStream(input), user);
|
||||
|
||||
assertThat(result.lastname, is(nullValue()));
|
||||
assertThat(result.address.zipCode, is("ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-348
|
||||
*/
|
||||
@Test
|
||||
public void appliesMergePatchCorrectly() throws Exception {
|
||||
|
||||
String input = "{ \"address\" : { \"zipCode\" : \"ZIP\"}, \"lastname\" : null }";
|
||||
|
||||
User result = handler.applyMergePatch(asStream(input), user);
|
||||
|
||||
assertThat(result.lastname, is(nullValue()));
|
||||
assertThat(result.address.zipCode, is("ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DATAREST-537
|
||||
*/
|
||||
@Test
|
||||
public void removesArrayItemCorrectly() throws Exception {
|
||||
|
||||
User thomas = new User();
|
||||
thomas.firstname = "Thomas";
|
||||
|
||||
User christoph = new User();
|
||||
christoph.firstname = "Christoph";
|
||||
|
||||
this.user.colleagues = Arrays.asList(thomas, christoph);
|
||||
|
||||
String input = "[{ \"op\": \"remove\", \"path\": \"/colleagues/0\" }]";
|
||||
|
||||
handler.applyPatch(asStream(input), user);
|
||||
|
||||
assertThat(user.colleagues, hasSize(1));
|
||||
assertThat(user.colleagues.get(0).firstname, is(christoph.firstname));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void hintsToMediaTypeIfBodyCantBeRead() throws Exception {
|
||||
|
||||
exception.expect(HttpMessageNotReadableException.class);
|
||||
exception.expectMessage(RestMediaTypes.JSON_PATCH_JSON.toString());
|
||||
|
||||
handler.applyPatch(asStream("{ \"foo\" : \"bar\" }"), new User());
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests to check the legacy representation is rendered if HAL is not the default media type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public class LegacyRepresentationConfigIntegrationTests extends AbstractRepositoryRestMvcConfigurationIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ MongoDbRepositoryConfig.class, RepositoryRestMvcConfiguration.class })
|
||||
static class Config extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
config.setDefaultMediaType(MediaType.APPLICATION_JSON);
|
||||
config.useHalAsDefaultJsonMediaType(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-213, DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void returnsJsonIfConfiguredAndRequested() throws Exception {
|
||||
|
||||
for (String resource : Arrays.asList("/", "/users")) {
|
||||
|
||||
mvc.perform(get(resource).accept(MediaType.APPLICATION_JSON)). //
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-213, DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void returnsJsonIfConfigured() throws Exception {
|
||||
|
||||
for (String resource : Arrays.asList("/", "/users")) {
|
||||
|
||||
mvc.perform(get(resource).accept(MediaType.ALL)). //
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.QuerydslRepositoryInvokerAdapter;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.webmvc.mongodb.QUser;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Receipt;
|
||||
import org.springframework.data.rest.webmvc.mongodb.ReceiptRepository;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QuerydslAwareRootResourceInformationHandlerMethodArgumentResolverUnitTests {
|
||||
|
||||
static final Map<String, String[]> NO_PARAMETERS = Collections.emptyMap();
|
||||
|
||||
@Mock Repositories repositories;
|
||||
@Mock RepositoryInvokerFactory invokerFactory;
|
||||
@Mock ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver;
|
||||
|
||||
@Mock RepositoryInvoker invoker;
|
||||
@Mock MethodParameter parameter;
|
||||
|
||||
QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver resolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
QuerydslBindingsFactory factory = new QuerydslBindingsFactory(SimpleEntityPathResolver.INSTANCE);
|
||||
ReflectionTestUtils.setField(factory, "repositories", repositories);
|
||||
QuerydslPredicateBuilder builder = new QuerydslPredicateBuilder(new DefaultConversionService(),
|
||||
factory.getEntityPathResolver());
|
||||
|
||||
this.resolver = new QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver(repositories, invokerFactory,
|
||||
resourceMetadataResolver, builder, factory);
|
||||
|
||||
when(parameter.hasParameterAnnotation(QuerydslPredicate.class)).thenReturn(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void returnsInvokerIfRepositoryIsNotQuerydslAware() {
|
||||
|
||||
ReceiptRepository repository = mock(ReceiptRepository.class);
|
||||
when(repositories.getRepositoryFor(Receipt.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, Receipt.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(invoker));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void wrapsInvokerInQuerydslAdapter() {
|
||||
|
||||
Object repository = mock(QuerydslUserRepository.class);
|
||||
when(repositories.getRepositoryFor(User.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, User.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(instanceOf(QuerydslRepositoryInvokerAdapter.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void invokesCustomizationOnRepositoryIfItImplementsCustomizer() {
|
||||
|
||||
QuerydslCustomizingUserRepository repository = mock(QuerydslCustomizingUserRepository.class);
|
||||
when(repositories.hasRepositoryFor(User.class)).thenReturn(true);
|
||||
when(repositories.getRepositoryFor(User.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, User.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(instanceOf(QuerydslRepositoryInvokerAdapter.class)));
|
||||
verify(repository, times(1)).customize(Mockito.any(QuerydslBindings.class), Mockito.any(QUser.class));
|
||||
}
|
||||
|
||||
interface QuerydslUserRepository extends QueryDslPredicateExecutor<User> {}
|
||||
|
||||
interface QuerydslCustomizingUserRepository
|
||||
extends QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> {}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* Base class for persistent classes.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
public class AbstractPersistentEntity {
|
||||
|
||||
@Id private final Long id;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the entity.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
protected AbstractPersistentEntity(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
protected AbstractPersistentEntity() {
|
||||
this.id = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractPersistentEntity that = (AbstractPersistentEntity) obj;
|
||||
|
||||
return this.id.equals(that.getId());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id == null ? 0 : id.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An address.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Address {
|
||||
|
||||
private final String street, city, country;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Address} from the given street, city and country.
|
||||
*
|
||||
* @param street must not be {@literal null} or empty.
|
||||
* @param city must not be {@literal null} or empty.
|
||||
* @param country must not be {@literal null} or empty.
|
||||
*/
|
||||
public Address(String street, String city, String country) {
|
||||
|
||||
Assert.hasText(street, "Street must not be null or empty!");
|
||||
Assert.hasText(city, "City must not be null or empty!");
|
||||
Assert.hasText(country, "Country must not be null or empty!");
|
||||
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the current {@link Address} instance which is a new entity in terms of persistence.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Address getCopy() {
|
||||
return new Address(this.street, this.city, this.country);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the street.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the city.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the country.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.gemfire.mapping.Region;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A customer.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Region
|
||||
public class Customer extends AbstractPersistentEntity {
|
||||
private EmailAddress emailAddress;
|
||||
private String firstname, lastname;
|
||||
private Set<Address> addresses = new HashSet<Address>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Customer} from the given parameters.
|
||||
*
|
||||
* @param id the unique id;
|
||||
* @param emailAddress must not be {@literal null} or empty.
|
||||
* @param firstname must not be {@literal null} or empty.
|
||||
* @param lastname must not be {@literal null} or empty.
|
||||
*/
|
||||
public Customer(Long id, EmailAddress emailAddress, String firstname, String lastname) {
|
||||
super(id);
|
||||
Assert.hasText(firstname);
|
||||
Assert.hasText(lastname);
|
||||
Assert.notNull(emailAddress);
|
||||
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
protected Customer() {}
|
||||
|
||||
/**
|
||||
* Adds the given {@link Address} to the {@link Customer}.
|
||||
*
|
||||
* @param address must not be {@literal null}.
|
||||
*/
|
||||
public void add(Address address) {
|
||||
|
||||
Assert.notNull(address);
|
||||
this.addresses.add(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the firstname of the {@link Customer}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the firstname of the {@link Customer}.
|
||||
*
|
||||
* @param firstname
|
||||
*/
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lastname of the {@link Customer}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lastname of the {@link Customer}.
|
||||
*
|
||||
* @param lastname
|
||||
*/
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EmailAddress} of the {@link Customer}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public EmailAddress getEmailAddress() {
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the emailAddress of the {@link Customer}.
|
||||
*
|
||||
* @param emailAddress
|
||||
*/
|
||||
public void setEmailAddress(EmailAddress emailAddress) {
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Customer}'s addresses.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<Address> getAddresses() {
|
||||
return Collections.unmodifiableSet(addresses);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.gemfire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* Repository interface to access {@link Customer}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
public interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||
|
||||
/**
|
||||
* Finds all {@link Customer}s with the given lastname.
|
||||
*
|
||||
* @param lastname
|
||||
* @return
|
||||
*/
|
||||
List<Customer> findByLastname(@Param("lastname") String lastname);
|
||||
|
||||
/**
|
||||
* Finds the Customer with the given {@link EmailAddress}.
|
||||
*
|
||||
* @param emailAddress
|
||||
* @return
|
||||
*/
|
||||
Customer findByEmailAddress(@Param("email") EmailAddress emailAddress);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
/**
|
||||
* Value object to represent email addresses.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
public final class EmailAddress {
|
||||
|
||||
private static final String EMAIL_REGEX = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
|
||||
private static final Pattern PATTERN = Pattern.compile(EMAIL_REGEX);
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EmailAddress} from the given {@link String} representation.
|
||||
*
|
||||
* @param emailAddress must not be {@literal null} or empty.
|
||||
*/
|
||||
@JsonCreator
|
||||
public EmailAddress(String emailAddress) {
|
||||
Assert.isTrue(isValid(emailAddress), "Invalid email address!");
|
||||
this.value = emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link String} is a valid {@link EmailAddress} which means you can safely instantiate the
|
||||
* class.
|
||||
*
|
||||
* @param candidate
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValid(String candidate) {
|
||||
return candidate == null ? false : PATTERN.matcher(candidate).matches();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof EmailAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EmailAddress that = (EmailAddress) obj;
|
||||
return this.value.equals(that.value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Component
|
||||
static class EmailAddressToStringConverter implements Converter<EmailAddress, String> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(EmailAddress source) {
|
||||
return source == null ? null : source.value;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
static class StringToEmailAddressConverter implements Converter<String, EmailAddress> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
public EmailAddress convert(String source) {
|
||||
return StringUtils.hasText(source) ? new EmailAddress(source) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
|
||||
import org.springframework.data.gemfire.mapping.Region;
|
||||
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
|
||||
import org.springframework.data.util.AnnotatedTypeScanner;
|
||||
|
||||
/**
|
||||
* Spring JavaConfig configuration class to setup a Spring container and infrastructure components.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Configuration
|
||||
@ImportResource("classpath:META-INF/spring/cache-config.xml")
|
||||
@EnableGemfireRepositories
|
||||
public class GemfireRepositoryConfig {
|
||||
|
||||
/**
|
||||
* TODO: Remove, once Spring Data Gemfire exposes a mapping context.
|
||||
*/
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
public GemfireMappingContext gemfireMappingContext() {
|
||||
|
||||
AnnotatedTypeScanner scanner = new AnnotatedTypeScanner(Region.class);
|
||||
|
||||
GemfireMappingContext context = new GemfireMappingContext();
|
||||
context.setInitialEntitySet(scanner.findTypes(GemfireRepositoryConfig.class.getPackage().getName()));
|
||||
context.initialize();
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.gemfire;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.data.rest.webmvc.CommonWebTests;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = GemfireRepositoryConfig.class)
|
||||
public class GemfireWebTests extends CommonWebTests {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels()
|
||||
*/
|
||||
@Override
|
||||
protected Iterable<String> expectedRootLinkRels() {
|
||||
return Arrays.asList("products");
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class LineItem {
|
||||
|
||||
private BigDecimal price;
|
||||
private int amount;
|
||||
private Long productId;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LineItem} for the given {@link Product}.
|
||||
*
|
||||
* @param product must not be {@literal null}.
|
||||
*/
|
||||
public LineItem(Product product) {
|
||||
this(product, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LineItem} for the given {@link Product} and amount.
|
||||
*
|
||||
* @param product must not be {@literal null}.
|
||||
* @param amount
|
||||
*/
|
||||
public LineItem(Product product, int amount) {
|
||||
Assert.notNull(product, "The given Product must not be null!");
|
||||
Assert.isTrue(amount > 0, "The amount of Products to be bought must be greater than 0!");
|
||||
|
||||
this.productId = product.getId();
|
||||
this.amount = amount;
|
||||
this.price = product.getPrice();
|
||||
}
|
||||
|
||||
protected LineItem() {}
|
||||
|
||||
/**
|
||||
* Returns the id of the {@link Product} the {@link LineItem} refers to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Long getProductId() {
|
||||
return productId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of {@link Product}s to be ordered.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the price a single unit of the {@link LineItem}'s product.
|
||||
*
|
||||
* @return the price
|
||||
*/
|
||||
public BigDecimal getUnitPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total for the {@link LineItem}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BigDecimal getTotal() {
|
||||
return price.multiply(BigDecimal.valueOf(amount));
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.gemfire.mapping.Region;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Region
|
||||
public class Order extends AbstractPersistentEntity {
|
||||
|
||||
private Long customerId;
|
||||
private Address billingAddress;
|
||||
private Address shippingAddress;
|
||||
private Set<LineItem> lineItems = new HashSet<LineItem>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Order} for the given {@link org.springframework.data.rest.webmvc.gemfire.Customer}.
|
||||
*
|
||||
* @param id order ID
|
||||
* @param customerId must not be {@literal null}.
|
||||
* @param shippingAddress must not be {@literal null}.
|
||||
*/
|
||||
public Order(Long id, Long customerId, Address shippingAddress) {
|
||||
super(id);
|
||||
Assert.notNull(customerId);
|
||||
Assert.notNull(shippingAddress);
|
||||
|
||||
this.customerId = customerId;
|
||||
this.shippingAddress = shippingAddress;
|
||||
}
|
||||
|
||||
protected Order() {}
|
||||
|
||||
/**
|
||||
* Adds the given {@link LineItem} to the {@link Order}.
|
||||
*
|
||||
* @param lineItem
|
||||
*/
|
||||
public void add(LineItem lineItem) {
|
||||
this.lineItems.add(lineItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the {@link org.springframework.data.rest.webmvc.gemfire.Customer} who placed the
|
||||
* {@link Order}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Long getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the billing {@link Address} for this order.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Address getBillingAddress() {
|
||||
return billingAddress != null ? billingAddress : shippingAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shipping {@link Address} for this order;
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Address getShippingAddress() {
|
||||
return shippingAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link LineItem}s currently belonging to the {@link Order}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<LineItem> getLineItems() {
|
||||
return Collections.unmodifiableSet(lineItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total of the {@link Order}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BigDecimal getTotal() {
|
||||
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
|
||||
for (LineItem item : lineItems) {
|
||||
total = total.add(item.getTotal());
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
public interface OrderRepository extends CrudRepository<Order, Long> {
|
||||
|
||||
List<Order> findByCustomerId(Long customerId);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 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.gemfire;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.gemfire.mapping.Region;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A product.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Region
|
||||
public class Product extends AbstractPersistentEntity {
|
||||
|
||||
private String name, description;
|
||||
private BigDecimal price;
|
||||
private Map<String, String> attributes = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Product} with the given name.
|
||||
*
|
||||
* @param id a unique Id
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param price must not be {@literal null} or less than or equal to zero.
|
||||
*/
|
||||
public Product(Long id, String name, BigDecimal price) {
|
||||
this(id, name, price, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Product} from the given name and description.
|
||||
*
|
||||
* @param id a unique Id
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param price must not be {@literal null} or less than or equal to zero.
|
||||
* @param description
|
||||
*/
|
||||
@PersistenceConstructor
|
||||
public Product(Long id, String name, BigDecimal price, String description) {
|
||||
super(id);
|
||||
Assert.hasText(name, "Name must not be null or empty!");
|
||||
Assert.isTrue(BigDecimal.ZERO.compareTo(price) < 0, "Price must be greater than zero!");
|
||||
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
protected Product() {}
|
||||
|
||||
/**
|
||||
* Sets the attribute with the given name to the given value.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param value
|
||||
*/
|
||||
public void setAttribute(String name, String value) {
|
||||
|
||||
Assert.hasText(name);
|
||||
|
||||
if (value == null) {
|
||||
this.attributes.remove(value);
|
||||
} else {
|
||||
this.attributes.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Product}'s name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Product}'s description.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the custom attributes of the {@link Product}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the price of the {@link Product}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BigDecimal getPrice() {
|
||||
return price;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.gemfire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.gemfire.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Repository interface to access {@link Product}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
*/
|
||||
public interface ProductRepository extends CrudRepository<Product, Long> {
|
||||
|
||||
/**
|
||||
* Returns a list of {@link Product}s having a description which contains the given snippet.
|
||||
*
|
||||
* @param the search string
|
||||
* @return
|
||||
*/
|
||||
List<Product> findByDescriptionContaining(String description);
|
||||
|
||||
/**
|
||||
* Returns all {@link Product}s having the given attribute value.
|
||||
*
|
||||
* @param attribute
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM /Product where attributes[$1] = $2")
|
||||
List<Product> findByAttributes(String key, String value);
|
||||
|
||||
List<Product> findByName(String name);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
public class Address {
|
||||
|
||||
public @Id @GeneratedValue Long id;
|
||||
public @Version Long version;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AddressRepository extends CrudRepository<Address, Long> {
|
||||
|
||||
@Override
|
||||
@RestResource(exported = false)
|
||||
Iterable<Address> findAll();
|
||||
|
||||
@Override
|
||||
@RestResource(exported = false)
|
||||
<S extends Address> S save(S entity);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.jpa;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
public class Author {
|
||||
|
||||
@Id @GeneratedValue//
|
||||
Long id;
|
||||
public String name;
|
||||
|
||||
@ManyToMany(mappedBy = "authors")//
|
||||
public Set<Book> books = new HashSet<Book>();
|
||||
|
||||
protected Author() {}
|
||||
|
||||
public Author(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AuthorRepository extends CrudRepository<Author, Long> {
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.data.rest.webmvc.RepositoryRestController;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Sample custom controller to test the ability to override
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RepositoryRestController
|
||||
public class AuthorsController {
|
||||
|
||||
@RequestMapping(value = "/authors/{author}", method = RequestMethod.DELETE)
|
||||
HttpEntity<?> deleteAuthor(@PathVariable Author author) {
|
||||
|
||||
Assert.notNull(author, "Author must not be null!");
|
||||
return new ResponseEntity<Object>(HttpStatus.I_AM_A_TEAPOT);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.jpa;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
public class Book {
|
||||
|
||||
@Id @GeneratedValue Long id;
|
||||
public String isbn;
|
||||
|
||||
@ManyToMany(cascade = { CascadeType.MERGE })//
|
||||
@RestResource(path = "creators") public Set<Author> authors;
|
||||
|
||||
public String title;
|
||||
|
||||
protected Book() {}
|
||||
|
||||
public Book(String isbn, String title, Iterable<Author> authors) {
|
||||
|
||||
this.isbn = isbn;
|
||||
this.title = title;
|
||||
|
||||
this.authors = new HashSet<Author>();
|
||||
|
||||
for (Author author : authors) {
|
||||
author.books.add(this);
|
||||
this.authors.add(author);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.data.rest.core.config.Projection;
|
||||
|
||||
/**
|
||||
* Interface for an excerpt projection for {@link Book}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Projection(name = "excerpt", types = Book.class)
|
||||
public interface BookExcerpt {
|
||||
|
||||
String getTitle();
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link BackendIdConverter} artificially transforming the actual book id into some magic {@link String} and back.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class BookIdConverter implements BackendIdConverter {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.support.BackendIdConverter#fromRequestId(java.lang.String, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Serializable fromRequestId(String id, Class<?> entityType) {
|
||||
return Long.parseLong(id.substring(0, id.indexOf('-')));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.support.BackendIdConverter#toRequestId(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public String toRequestId(Serializable id, Class<?> entityType) {
|
||||
|
||||
Long longId = (Long) id;
|
||||
List<Long> ids = new ArrayList<Long>(longId.intValue());
|
||||
|
||||
for (int i = 0; i < longId; i++) {
|
||||
ids.add(longId);
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(ids, "-");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> delimiter) {
|
||||
return Book.class.equals(delimiter);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RepositoryRestResource(excerptProjection = BookExcerpt.class)
|
||||
public interface BookRepository extends CrudRepository<Book, Long> {
|
||||
|
||||
@RestResource(rel = "find-by-sorted")
|
||||
List<Book> findBy(Sort sort);
|
||||
|
||||
@Query("select b from Book b where :author member of b.authors")
|
||||
List<Book> findByAuthorsContains(@Param("author") Author author);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
public class CreditCard {
|
||||
|
||||
@Id Long id;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface CreditCardRepository extends CrudRepository<CreditCard, Long> {
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
|
||||
import org.springframework.data.jpa.mapping.JpaPersistentEntity;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Integration tests for DATAREST-262, checking serialization and deserialization of associations within embeddables.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class DataRest262Tests {
|
||||
|
||||
@Configuration
|
||||
@Import({ RepositoryRestMvcConfiguration.class, JpaInfrastructureConfig.class })
|
||||
@EnableJpaRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
@Autowired ApplicationContext beanFactory;
|
||||
@Autowired JpaMetamodelMappingContext mappingContext;
|
||||
@Autowired AirportRepository repository;
|
||||
@Autowired @Qualifier("halObjectMapper") ObjectMapper mapper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-262
|
||||
*/
|
||||
@Test
|
||||
public void deserializesNestedAssociation() throws Exception {
|
||||
|
||||
Airport airport = repository.save(new Airport());
|
||||
String payload = "{\"orgOrDstFlightPart\":{\"airport\":\"/api/airports/" + airport.id + "\"}}";
|
||||
|
||||
AircraftMovement result = mapper.readValue(payload, AircraftMovement.class);
|
||||
assertThat(result.orgOrDstFlightPart.airport.id, is(airport.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-262
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void serializesLinksToNestedAssociations() throws Exception {
|
||||
|
||||
Airport first = new Airport();
|
||||
first.id = 1L;
|
||||
|
||||
Airport second = new Airport();
|
||||
second.id = 2L;
|
||||
|
||||
FlightPart part = new FlightPart();
|
||||
part.airport = second;
|
||||
|
||||
AircraftMovement movement = new AircraftMovement();
|
||||
movement.id = 3L;
|
||||
movement.originOrDestinationAirport = first;
|
||||
movement.orgOrDstFlightPart = part;
|
||||
|
||||
JpaPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(AircraftMovement.class);
|
||||
|
||||
Resource<Object> resource = PersistentEntityResource.build(movement, persistentEntity).//
|
||||
withLink(new Link("/api/airports/" + movement.id)).//
|
||||
build();
|
||||
|
||||
String result = mapper.writeValueAsString(resource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_links.self"), is(notNullValue()));
|
||||
assertThat(JsonPath.read(result, "$_links.airport"), is(notNullValue()));
|
||||
assertThat(JsonPath.read(result, "$_links.originOrDestinationAirport"), is(notNullValue()));
|
||||
}
|
||||
|
||||
public interface AircraftMovementRepository extends CrudRepository<AircraftMovement, Long> {
|
||||
|
||||
}
|
||||
|
||||
public interface AirportRepository extends CrudRepository<Airport, Long> {
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "aircraftmovement")
|
||||
public static class AircraftMovement {
|
||||
|
||||
@Id @GeneratedValue Long id;
|
||||
@ManyToOne Airport originOrDestinationAirport;
|
||||
@Embedded @NotNull FlightPart orgOrDstFlightPart;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class FlightPart {
|
||||
@ManyToOne Airport airport;
|
||||
}
|
||||
|
||||
@Entity(name = "airport")
|
||||
public static class Airport {
|
||||
@Id @GeneratedValue Long id;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-463
|
||||
*/
|
||||
@Entity
|
||||
public class Item {
|
||||
|
||||
private @Id @GeneratedValue Long id;
|
||||
private String name;
|
||||
private @JsonIgnore @OneToOne User owner;
|
||||
private @OneToOne User manager, curator;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public User getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(User owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public User getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public void setManager(User manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public User getCurator() {
|
||||
return curator;
|
||||
}
|
||||
|
||||
public void setCurator(User curator) {
|
||||
this.curator = curator;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-463
|
||||
*/
|
||||
public interface ItemRepository extends CrudRepository<Item, Long> {}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
public class JpaInfrastructureConfig {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
|
||||
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
vendorAdapter.setDatabase(Database.HSQL);
|
||||
vendorAdapter.setGenerateDdl(true);
|
||||
|
||||
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||
factory.setJpaVendorAdapter(vendorAdapter);
|
||||
factory.setPackagesToScan(getClass().getPackage().getName());
|
||||
factory.setPersistenceUnitName("spring-data-rest-webmvc");
|
||||
factory.setDataSource(dataSource());
|
||||
factory.afterPropertiesSet();
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return new JpaTransactionManager();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.rest.webmvc.BasePathAwareController;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Test configuration for JPA.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
@EnableJpaRepositories
|
||||
@EnableTransactionManagement
|
||||
public class JpaRepositoryConfig extends JpaInfrastructureConfig {
|
||||
|
||||
@Bean
|
||||
public BookIdConverter bookIdConverter() {
|
||||
return new BookIdConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestDataPopulator testDataPopulator() {
|
||||
return new TestDataPopulator();
|
||||
}
|
||||
|
||||
@BasePathAwareController
|
||||
static class BooksHtmlController {
|
||||
|
||||
@RequestMapping(value = "/books/{id}", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
|
||||
void person(@PathVariable String id) {}
|
||||
}
|
||||
}
|
||||
@@ -1,721 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.jpa;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.rest.webmvc.util.TestUtils.*;
|
||||
import static org.springframework.http.HttpHeaders.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.webmvc.CommonWebTests;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Web integration tests specific to JPA.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Transactional
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
public class JpaWebTests extends CommonWebTests {
|
||||
|
||||
private static final MediaType TEXT_URI_LIST = MediaType.valueOf("text/uri-list");
|
||||
static final String LINK_TO_SIBLINGS_OF = "$._embedded..[?(@.firstName == '%s')]._links.siblings.href[0]";
|
||||
|
||||
@Autowired TestDataPopulator loader;
|
||||
@Autowired ResourceMappings mappings;
|
||||
@Autowired RelProvider relProvider;
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#setUp()
|
||||
*/
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() {
|
||||
loader.populateRepositories();
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels()
|
||||
*/
|
||||
@Override
|
||||
protected Iterable<String> expectedRootLinkRels() {
|
||||
return Arrays.asList("people", "authors", "books");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#getPayloadToPost()
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, String> getPayloadToPost() throws Exception {
|
||||
return Collections.singletonMap("people", readFileFromClasspath("person.json"));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#getRootAndLinkedResources()
|
||||
*/
|
||||
@Override
|
||||
protected MultiValueMap<String, String> getRootAndLinkedResources() {
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
|
||||
map.add("authors", "books");
|
||||
map.add("books", "authors");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-99
|
||||
*/
|
||||
@Test
|
||||
public void doesNotExposeCreditCardRepository() throws Exception {
|
||||
|
||||
mvc.perform(get("/")). //
|
||||
andExpect(status().isOk()). //
|
||||
andExpect(doesNotHaveLinkWithRel(mappings.getMetadataFor(CreditCard.class).getRel()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessPersons() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request("/people?page=0&size=1");
|
||||
|
||||
Link nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response);
|
||||
assertDoesNotHaveLinkWithRel(Link.REL_PREVIOUS, response);
|
||||
|
||||
response = client.request(nextLink);
|
||||
client.assertHasLinkWithRel(Link.REL_PREVIOUS, response);
|
||||
nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response);
|
||||
|
||||
response = client.request(nextLink);
|
||||
client.assertHasLinkWithRel(Link.REL_PREVIOUS, response);
|
||||
assertDoesNotHaveLinkWithRel(Link.REL_NEXT, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-169
|
||||
*/
|
||||
@Test
|
||||
public void exposesLinkForRelatedResource() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
Link ordersLink = client.assertHasLinkWithRel("orders", response);
|
||||
|
||||
MockHttpServletResponse orders = client.request(ordersLink);
|
||||
Link creatorLink = assertHasContentLinkWithRel("creator", orders);
|
||||
|
||||
assertThat(client.request(creatorLink), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-200
|
||||
*/
|
||||
@Test
|
||||
public void exposesInlinedEntities() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request("/");
|
||||
Link ordersLink = client.assertHasLinkWithRel("orders", response);
|
||||
|
||||
MockHttpServletResponse orders = client.request(ordersLink);
|
||||
assertHasJsonPathValue("$..lineItems", orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-199
|
||||
*/
|
||||
@Test
|
||||
public void createsOrderUsingPut() throws Exception {
|
||||
|
||||
mvc.perform(//
|
||||
put("/orders/{id}", 4711).//
|
||||
content(readFileFromClasspath("order.json")).contentType(MediaType.APPLICATION_JSON)//
|
||||
).andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-117
|
||||
*/
|
||||
@Test
|
||||
public void createPersonThenVerifyIgnoredAttributesDontExist() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Person frodo = new Person("Frodo", "Baggins");
|
||||
frodo.setAge(77);
|
||||
frodo.setHeight(42);
|
||||
frodo.setWeight(75);
|
||||
String frodoString = mapper.writeValueAsString(frodo);
|
||||
|
||||
MockHttpServletResponse response = postAndGet(peopleLink, frodoString, MediaType.APPLICATION_JSON);
|
||||
|
||||
assertJsonPathEquals("$.firstName", "Frodo", response);
|
||||
assertJsonPathEquals("$.lastName", "Baggins", response);
|
||||
assertJsonPathDoesntExist("$.age", response);
|
||||
assertJsonPathDoesntExist("$.height", response);
|
||||
assertJsonPathDoesntExist("$.weight", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-95
|
||||
*/
|
||||
@Test
|
||||
public void createThenPatch() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
|
||||
MockHttpServletResponse bilbo = postAndGet(peopleLink, "{ \"firstName\" : \"Bilbo\", \"lastName\" : \"Baggins\" }",
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
Link bilboLink = client.assertHasLinkWithRel("self", bilbo);
|
||||
|
||||
assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.firstName"), is("Bilbo"));
|
||||
assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.lastName"), is("Baggins"));
|
||||
|
||||
MockHttpServletResponse frodo = patchAndGet(bilboLink, "{ \"firstName\" : \"Frodo\" }", MediaType.APPLICATION_JSON);
|
||||
|
||||
assertThat((String) JsonPath.read(frodo.getContentAsString(), "$.firstName"), is("Frodo"));
|
||||
assertThat((String) JsonPath.read(frodo.getContentAsString(), "$.lastName"), is("Baggins"));
|
||||
|
||||
frodo = patchAndGet(bilboLink, "{ \"firstName\" : null }", MediaType.APPLICATION_JSON);
|
||||
|
||||
assertThat((String) JsonPath.read(frodo.getContentAsString(), "$.firstName"), is(nullValue()));
|
||||
assertThat((String) JsonPath.read(frodo.getContentAsString(), "$.lastName"), is("Baggins"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-150
|
||||
*/
|
||||
@Test
|
||||
public void createThenPut() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
|
||||
MockHttpServletResponse bilbo = postAndGet(peopleLink, //
|
||||
"{ \"firstName\" : \"Bilbo\", \"lastName\" : \"Baggins\" }", //
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
Link bilboLink = client.assertHasLinkWithRel("self", bilbo);
|
||||
|
||||
assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.firstName"), equalTo("Bilbo"));
|
||||
assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.lastName"), equalTo("Baggins"));
|
||||
|
||||
MockHttpServletResponse frodo = putAndGet(bilboLink, //
|
||||
"{ \"firstName\" : \"Frodo\" }", //
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
assertThat((String) JsonPath.read(frodo.getContentAsString(), "$.firstName"), equalTo("Frodo"));
|
||||
assertNull(JsonPath.read(frodo.getContentAsString(), "$.lastName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listsSiblingsWithContentCorrectly() throws Exception {
|
||||
assertPersonWithNameAndSiblingLink("John");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listsEmptySiblingsCorrectly() throws Exception {
|
||||
assertPersonWithNameAndSiblingLink("Billy Bob");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-219
|
||||
*/
|
||||
@Test
|
||||
public void manipulatePropertyCollectionRestfullyWithMultiplePosts() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"), //
|
||||
new Person("Merry", "Baggins"), //
|
||||
new Person("Pippin", "Baggins"));
|
||||
|
||||
Link frodosSiblingLink = links.get(0);
|
||||
|
||||
patchAndGet(frodosSiblingLink, links.get(1).getHref(), TEXT_URI_LIST);
|
||||
patchAndGet(frodosSiblingLink, links.get(2).getHref(), TEXT_URI_LIST);
|
||||
patchAndGet(frodosSiblingLink, links.get(3).getHref(), TEXT_URI_LIST);
|
||||
|
||||
assertSiblingNames(frodosSiblingLink, "Bilbo", "Merry", "Pippin");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-219
|
||||
*/
|
||||
@Test
|
||||
public void manipulatePropertyCollectionRestfullyWithSinglePost() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"), //
|
||||
new Person("Merry", "Baggins"), //
|
||||
new Person("Pippin", "Baggins"));
|
||||
|
||||
Link frodosSiblingLink = links.get(0);
|
||||
|
||||
patchAndGet(frodosSiblingLink, toUriList(links.get(1), links.get(2), links.get(3)), TEXT_URI_LIST);
|
||||
|
||||
assertSiblingNames(frodosSiblingLink, "Bilbo", "Merry", "Pippin");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-219
|
||||
*/
|
||||
@Test
|
||||
public void manipulatePropertyCollectionRestfullyWithMultiplePuts() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"), //
|
||||
new Person("Merry", "Baggins"), //
|
||||
new Person("Pippin", "Baggins"));
|
||||
|
||||
Link frodosSiblingsLink = links.get(0);
|
||||
|
||||
putAndGet(frodosSiblingsLink, links.get(1).expand().getHref(), TEXT_URI_LIST);
|
||||
putAndGet(frodosSiblingsLink, links.get(2).expand().getHref(), TEXT_URI_LIST);
|
||||
putAndGet(frodosSiblingsLink, links.get(3).expand().getHref(), TEXT_URI_LIST);
|
||||
assertSiblingNames(frodosSiblingsLink, "Pippin");
|
||||
|
||||
patchAndGet(frodosSiblingsLink, links.get(2).getHref(), TEXT_URI_LIST);
|
||||
assertSiblingNames(frodosSiblingsLink, "Merry", "Pippin");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-219
|
||||
*/
|
||||
@Test
|
||||
public void manipulatePropertyCollectionRestfullyWithSinglePut() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"), //
|
||||
new Person("Merry", "Baggins"), //
|
||||
new Person("Pippin", "Baggins"));
|
||||
|
||||
Link frodoSiblingLink = links.get(0);
|
||||
|
||||
putAndGet(frodoSiblingLink, toUriList(links.get(1), links.get(2), links.get(3)), TEXT_URI_LIST);
|
||||
assertSiblingNames(frodoSiblingLink, "Bilbo", "Merry", "Pippin");
|
||||
|
||||
putAndGet(frodoSiblingLink, toUriList(links.get(3)), TEXT_URI_LIST);
|
||||
assertSiblingNames(frodoSiblingLink, "Pippin");
|
||||
|
||||
patchAndGet(frodoSiblingLink, toUriList(links.get(2)), TEXT_URI_LIST);
|
||||
assertSiblingNames(frodoSiblingLink, "Merry", "Pippin");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-219
|
||||
*/
|
||||
@Test
|
||||
public void manipulatePropertyCollectionRestfullyWithDelete() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"), //
|
||||
new Person("Merry", "Baggins"), //
|
||||
new Person("Pippin", "Baggins"));
|
||||
|
||||
Link frodosSiblingsLink = links.get(0);
|
||||
|
||||
patchAndGet(frodosSiblingsLink, links.get(1).getHref(), TEXT_URI_LIST);
|
||||
patchAndGet(frodosSiblingsLink, links.get(2).getHref(), TEXT_URI_LIST);
|
||||
patchAndGet(frodosSiblingsLink, links.get(3).getHref(), TEXT_URI_LIST);
|
||||
|
||||
String pippinId = new UriTemplate("/people/{id}").match(links.get(3).getHref()).get("id");
|
||||
deleteAndVerify(new Link(frodosSiblingsLink.getHref() + "/" + pippinId));
|
||||
|
||||
assertSiblingNames(frodosSiblingsLink, "Bilbo", "Merry");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-50
|
||||
*/
|
||||
@Test
|
||||
public void propertiesCanHaveNulls() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
|
||||
Person frodo = new Person();
|
||||
frodo.setFirstName("Frodo");
|
||||
frodo.setLastName(null);
|
||||
|
||||
MockHttpServletResponse response = postAndGet(peopleLink, mapper.writeValueAsString(frodo),
|
||||
MediaType.APPLICATION_JSON);
|
||||
String responseBody = response.getContentAsString();
|
||||
|
||||
assertEquals(JsonPath.read(responseBody, "$.firstName"), "Frodo");
|
||||
assertNull(JsonPath.read(responseBody, "$.lastName"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-238
|
||||
*/
|
||||
@Test
|
||||
public void putShouldWorkDespiteExistingLinks() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
|
||||
Person frodo = new Person("Frodo", "Baggins");
|
||||
String frodoString = mapper.writeValueAsString(frodo);
|
||||
|
||||
MockHttpServletResponse createdPerson = postAndGet(peopleLink, frodoString, MediaType.APPLICATION_JSON);
|
||||
|
||||
Link frodoLink = client.assertHasLinkWithRel("self", createdPerson);
|
||||
assertJsonPathEquals("$.firstName", "Frodo", createdPerson);
|
||||
|
||||
String bilboWithFrodosLinks = createdPerson.getContentAsString().replace("Frodo", "Bilbo");
|
||||
|
||||
MockHttpServletResponse overwrittenResponse = putAndGet(frodoLink, bilboWithFrodosLinks,
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
client.assertHasLinkWithRel("self", overwrittenResponse);
|
||||
assertJsonPathEquals("$.firstName", "Bilbo", overwrittenResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test
|
||||
public void doesNotAllowGetToCollectionResourceIfFindAllIsNotExported() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("addresses");
|
||||
|
||||
mvc.perform(get(link.getHref())).//
|
||||
andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-217
|
||||
*/
|
||||
@Test
|
||||
public void doesNotAllowPostToCollectionResourceIfSaveIsNotExported() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("addresses");
|
||||
|
||||
mvc.perform(post(link.getHref()).content("{}").contentType(MediaType.APPLICATION_JSON)).//
|
||||
andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, that the server only returns the properties contained in the projection requested.
|
||||
*
|
||||
* @see OrderSummary
|
||||
* @see DATAREST-221
|
||||
*/
|
||||
@Test
|
||||
public void returnsProjectionIfRequested() throws Exception {
|
||||
|
||||
Link orders = client.discoverUnique("orders");
|
||||
|
||||
MockHttpServletResponse response = client.request(orders);
|
||||
Link orderLink = assertContentLinkWithRel("self", response, true).expand();
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(orderLink.getHref());
|
||||
String uri = builder.queryParam("projection", "summary").build().toUriString();
|
||||
|
||||
response = mvc.perform(get(uri)). //
|
||||
andExpect(status().isOk()). //
|
||||
andExpect(jsonPath("$.price", is(2.5))).//
|
||||
andReturn().getResponse();
|
||||
|
||||
assertJsonPathDoesntExist("$.lineItems", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-261
|
||||
*/
|
||||
@Test
|
||||
public void relProviderDetectsCustomizedMapping() {
|
||||
assertThat(relProvider.getCollectionResourceRelFor(Person.class), is("people"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-311
|
||||
*/
|
||||
@Test
|
||||
public void onlyLinksShouldAppearWhenExecuteSearchCompact() throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
Person daenerys = new Person("Daenerys", "Targaryen");
|
||||
String daenerysString = mapper.writeValueAsString(daenerys);
|
||||
|
||||
MockHttpServletResponse createdPerson = postAndGet(peopleLink, daenerysString, MediaType.APPLICATION_JSON);
|
||||
Link daenerysLink = client.assertHasLinkWithRel("self", createdPerson);
|
||||
assertJsonPathEquals("$.firstName", "Daenerys", createdPerson);
|
||||
|
||||
Link searchLink = client.discoverUnique(peopleLink, "search");
|
||||
Link byFirstNameLink = client.discoverUnique(searchLink, "findFirstPersonByFirstName");
|
||||
|
||||
MockHttpServletResponse response = client.request(byFirstNameLink.expand("Daenerys"),
|
||||
MediaType.parseMediaType("application/x-spring-data-compact+json"));
|
||||
|
||||
String responseBody = response.getContentAsString();
|
||||
|
||||
JSONArray personLinks = JsonPath.<JSONArray> read(responseBody, "$.links[?(@.rel=='person')].href");
|
||||
|
||||
assertThat(personLinks, hasSize(1));
|
||||
assertThat(personLinks.get(0), is((Object) daenerysLink.getHref()));
|
||||
assertThat(JsonPath.<JSONArray> read(responseBody, "$.content"), hasSize(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-317
|
||||
*/
|
||||
@Test
|
||||
public void rendersExcerptProjectionsCorrectly() throws Exception {
|
||||
|
||||
Link authorsLink = client.discoverUnique("authors");
|
||||
|
||||
MockHttpServletResponse response = client.request(authorsLink);
|
||||
String firstAuthorPath = "$._embedded.authors[0]";
|
||||
|
||||
// Has main content
|
||||
assertHasJsonPathValue(firstAuthorPath.concat(".name"), response);
|
||||
|
||||
// Embeddes content of related entity, self link and keeps relation link
|
||||
assertHasJsonPathValue(firstAuthorPath.concat("._embedded.books[0].title"), response);
|
||||
assertHasJsonPathValue(firstAuthorPath.concat("._embedded.books[0]._links.self"), response);
|
||||
assertHasJsonPathValue(firstAuthorPath.concat("._links.books"), response);
|
||||
|
||||
// Access item resource and expect link to related resource present
|
||||
String content = response.getContentAsString();
|
||||
String href = JsonPath.read(content, firstAuthorPath.concat("._links.self.href"));
|
||||
|
||||
client.follow(new Link(href)).andExpect(client.hasLinkWithRel("books"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-353
|
||||
*/
|
||||
@Test
|
||||
public void returns404WhenTryingToDeleteANonExistingResource() throws Exception {
|
||||
|
||||
Link receiptsLink = client.discoverUnique("receipts");
|
||||
|
||||
mvc.perform(delete(receiptsLink.getHref().concat("/{id}"), 4711)).//
|
||||
andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-384
|
||||
*/
|
||||
@Test
|
||||
public void execturesSearchThatTakesASort() throws Exception {
|
||||
|
||||
Link booksLink = client.discoverUnique("books");
|
||||
Link searchLink = client.discoverUnique(booksLink, "search");
|
||||
Link findBySortedLink = client.discoverUnique(searchLink, "find-by-sorted");
|
||||
|
||||
// Assert sort options advertised
|
||||
assertThat(findBySortedLink.isTemplated(), is(true));
|
||||
assertThat(findBySortedLink.getVariableNames(), hasItems("sort", "projection"));
|
||||
|
||||
// Assert results returned as specified
|
||||
client.follow(findBySortedLink.expand("title,desc")).//
|
||||
andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data (Second Edition)")).//
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data")).//
|
||||
andExpect(client.hasLinkWithRel("self"));
|
||||
|
||||
client.follow(findBySortedLink.expand("title,asc")).//
|
||||
andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data")).//
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data (Second Edition)")).//
|
||||
andExpect(client.hasLinkWithRel("self"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-160
|
||||
*/
|
||||
@Test
|
||||
public void returnConflictWhenConcurrentlyEditingVersionedEntity() throws Exception {
|
||||
|
||||
Link receiptLink = client.discoverUnique("receipts");
|
||||
|
||||
Receipt receipt = new Receipt();
|
||||
receipt.setAmount(new BigDecimal(50));
|
||||
receipt.setSaleItem("Springy Tacos");
|
||||
|
||||
String stringReceipt = mapper.writeValueAsString(receipt);
|
||||
|
||||
MockHttpServletResponse createdReceipt = postAndGet(receiptLink, stringReceipt, MediaType.APPLICATION_JSON);
|
||||
Link tacosLink = client.assertHasLinkWithRel("self", createdReceipt);
|
||||
assertJsonPathEquals("$.saleItem", "Springy Tacos", createdReceipt);
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(tacosLink.getHref());
|
||||
String concurrencyTag = createdReceipt.getHeader("ETag");
|
||||
|
||||
mvc.perform(patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyBurritos\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, concurrencyTag))
|
||||
.andExpect(status().is2xxSuccessful());
|
||||
|
||||
mvc.perform(patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyTequila\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, "\"falseETag\""))
|
||||
.andExpect(status().isPreconditionFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-423
|
||||
*/
|
||||
@Test
|
||||
public void invokesCustomControllerAndBindsDomainObjectCorrectly() throws Exception {
|
||||
|
||||
MockHttpServletResponse authorsResponse = client.request(client.discoverUnique("authors"));
|
||||
|
||||
String authorUri = JsonPath.read(authorsResponse.getContentAsString(), "$._embedded.authors[0]._links.self.href");
|
||||
|
||||
mvc.perform(delete(authorUri)).//
|
||||
andExpect(status().isIAmATeapot());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-523
|
||||
*/
|
||||
@Test
|
||||
public void augmentsCollectionAssociationUsingPost() throws Exception {
|
||||
|
||||
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
|
||||
new Person("Bilbo", "Baggins"));
|
||||
|
||||
Link frodosSiblingsLink = links.get(0).expand();
|
||||
Link bilboLink = links.get(1);
|
||||
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
|
||||
mvc.perform(post(frodosSiblingsLink.getHref()).//
|
||||
content(bilboLink.getHref()).//
|
||||
contentType(TEXT_URI_LIST)).//
|
||||
andExpect(status().isNoContent());
|
||||
|
||||
mvc.perform(get(frodosSiblingsLink.getHref())).//
|
||||
andExpect(jsonPath("$._embedded.people", hasSize(i)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-658
|
||||
*/
|
||||
@Test
|
||||
public void returnsLinkHeadersForHeadRequestToItemResource() throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request(client.discoverUnique("people"));
|
||||
String personHref = JsonPath.read(response.getContentAsString(), "$._embedded.people[0]._links.self.href");
|
||||
|
||||
response = mvc.perform(head(personHref))//
|
||||
.andExpect(status().isNoContent())//
|
||||
.andReturn().getResponse();
|
||||
|
||||
Links links = Links.valueOf(response.getHeader("Link"));
|
||||
assertThat(links.hasLink("self"), is(true));
|
||||
assertThat(links.hasLink("person"), is(true));
|
||||
}
|
||||
|
||||
private List<Link> preparePersonResources(Person primary, Person... persons) throws Exception {
|
||||
|
||||
Link peopleLink = client.discoverUnique("people");
|
||||
List<Link> links = new ArrayList<Link>();
|
||||
|
||||
MockHttpServletResponse primaryResponse = postAndGet(peopleLink, mapper.writeValueAsString(primary),
|
||||
MediaType.APPLICATION_JSON);
|
||||
links.add(client.assertHasLinkWithRel("siblings", primaryResponse));
|
||||
|
||||
for (Person person : persons) {
|
||||
|
||||
String payload = mapper.writeValueAsString(person);
|
||||
MockHttpServletResponse response = postAndGet(peopleLink, payload, MediaType.APPLICATION_JSON);
|
||||
|
||||
links.add(client.assertHasLinkWithRel(Link.REL_SELF, response));
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the {@link Person} resource the given link points to contains siblings with the given names.
|
||||
*
|
||||
* @param link
|
||||
* @param siblingNames
|
||||
* @throws Exception
|
||||
*/
|
||||
private void assertSiblingNames(Link link, String... siblingNames) throws Exception {
|
||||
|
||||
String responseBody = client.request(link).getContentAsString();
|
||||
List<String> persons = JsonPath.read(responseBody, "$._embedded.people[*].firstName");
|
||||
|
||||
assertThat(persons, hasSize(siblingNames.length));
|
||||
assertThat(persons, hasItems(siblingNames));
|
||||
}
|
||||
|
||||
private void assertPersonWithNameAndSiblingLink(String name) throws Exception {
|
||||
|
||||
MockHttpServletResponse response = client.request(client.discoverUnique("people"));
|
||||
|
||||
String jsonPath = String.format("$._embedded.people[?(@.firstName == '%s')][0]", name);
|
||||
|
||||
// Assert content inlined
|
||||
Object john = JsonPath.read(response.getContentAsString(), jsonPath);
|
||||
assertThat(john, is(notNullValue()));
|
||||
assertThat(JsonPath.read(john, "$.firstName"), is(notNullValue()));
|
||||
|
||||
// Assert sibling link exposed in resource pointed to
|
||||
Link selfLink = new Link(JsonPath.<String> read(john, "$._links.self.href"));
|
||||
client.follow(selfLink).//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(jsonPath("$._links.siblings", is(notNullValue())));
|
||||
}
|
||||
|
||||
private static String toUriList(Link... links) {
|
||||
|
||||
List<String> uris = new ArrayList<String>(links.length);
|
||||
|
||||
for (Link link : links) {
|
||||
uris.add(link.expand().getHref());
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(uris, "\n");
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
public class LineItem {
|
||||
|
||||
@Id @GeneratedValue//
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public LineItem(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected LineItem() {
|
||||
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "ORDERS")
|
||||
public class Order {
|
||||
|
||||
@Id @GeneratedValue//
|
||||
private Long id;
|
||||
@ManyToOne(fetch = FetchType.LAZY)//
|
||||
private Person creator;
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)//
|
||||
private List<LineItem> lineItems = new ArrayList<LineItem>();
|
||||
private Type type = Type.TAKE_AWAY;
|
||||
|
||||
public Order(Person creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
protected Order() {
|
||||
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Person getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lineItems
|
||||
*/
|
||||
public List<LineItem> getLineItems() {
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public void add(LineItem item) {
|
||||
this.lineItems.add(item);
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
return new BigDecimal(2.50);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RepositoryRestResource(collectionResourceDescription = @Description("Collection resource description"),
|
||||
itemResourceDescription = @Description("Item resource description."))
|
||||
public interface OrderRepository extends CrudRepository<Order, Long> {
|
||||
|
||||
List<Order> findByType(@Param("type") Type type);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
import org.springframework.data.rest.core.config.Projection;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Projection(name = "summary", types = Order.class)
|
||||
@Description("A summary of an order.")
|
||||
public interface OrderSummary {
|
||||
|
||||
@Description("Price!!")
|
||||
BigDecimal getPrice();
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.data.rest.core.annotation.Description;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* An entity that represents a person.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Entity
|
||||
@JsonIgnoreProperties({ "height", "weight" })
|
||||
public class Person {
|
||||
|
||||
@Id @GeneratedValue private Long id;
|
||||
|
||||
@Description("A person's first name") //
|
||||
private String firstName;
|
||||
|
||||
@Description("A person's last name") //
|
||||
private String lastName;
|
||||
|
||||
@Description("A person's siblings") //
|
||||
@ManyToMany //
|
||||
private List<Person> siblings = new ArrayList<Person>();
|
||||
|
||||
@ManyToOne //
|
||||
private Person father;
|
||||
|
||||
@Description("Timestamp this person object was created") //
|
||||
private Date created;
|
||||
|
||||
@JsonIgnore //
|
||||
private int age;
|
||||
|
||||
private int height, weight;
|
||||
private Gender gender;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Person addSibling(Person p) {
|
||||
|
||||
if (siblings == Collections.EMPTY_LIST) {
|
||||
siblings = new ArrayList<Person>();
|
||||
}
|
||||
|
||||
siblings.add(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Person> getSiblings() {
|
||||
return siblings;
|
||||
}
|
||||
|
||||
public void setSiblings(List<Person> siblings) {
|
||||
this.siblings = siblings;
|
||||
}
|
||||
|
||||
public Person getFather() {
|
||||
return father;
|
||||
}
|
||||
|
||||
public void setFather(Person father) {
|
||||
this.father = father;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {}
|
||||
|
||||
@PrePersist
|
||||
private void prePersist() {
|
||||
this.created = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public Gender getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(Gender gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public static enum Gender {
|
||||
MALE, FEMALE, UNDEFINED;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RepositoryRestResource(collectionResourceRel = "people", path = "people")
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
|
||||
|
||||
@RestResource(rel = "firstname", path = "firstname")
|
||||
Page<Person> findByFirstName(@Param("firstname") String firstName, Pageable pageable);
|
||||
|
||||
@RestResource(rel = "lastname", path = "lastname")
|
||||
List<Person> findByLastName(@Param("lastname") String lastName, Sort sort);
|
||||
|
||||
Person findFirstPersonByFirstName(@Param("firstname") String firstName);
|
||||
|
||||
Page<Person> findByCreatedGreaterThan(@Param("date") Date date, Pageable pageable);
|
||||
|
||||
@Query("select p from Person p where p.created > :date")
|
||||
Page<Person> findByCreatedUsingISO8601Date(@Param("date") @DateTimeFormat(iso = ISO.DATE_TIME) Date date,
|
||||
Pageable pageable);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.data.rest.core.config.Projection;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Projection(name = "excerpt", types = Person.class)
|
||||
public interface PersonSummary {
|
||||
|
||||
String getFirstName();
|
||||
|
||||
String getLastName();
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Entity;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* An entity that represents a receipt.
|
||||
*
|
||||
* @author Pablo Lozano
|
||||
*/
|
||||
@Entity
|
||||
@JsonIgnoreProperties({"version"})
|
||||
public class Receipt {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String saleItem;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
@Version
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date version;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getSaleItem() {
|
||||
return saleItem;
|
||||
}
|
||||
|
||||
public void setSaleItem(String saleItem) {
|
||||
this.saleItem = saleItem;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
|
||||
public Date getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Date version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Receipt}s.
|
||||
*
|
||||
* @author Pablo Lozano
|
||||
*/
|
||||
|
||||
public interface ReceiptRepository extends CrudRepository<Receipt, Long> {
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.jpa;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class TestDataPopulator {
|
||||
|
||||
@Autowired PersonRepository people;
|
||||
@Autowired OrderRepository orders;
|
||||
@Autowired AuthorRepository authors;
|
||||
@Autowired BookRepository books;
|
||||
|
||||
public void populateRepositories() {
|
||||
|
||||
books.deleteAll();
|
||||
authors.deleteAll();
|
||||
orders.deleteAll();
|
||||
people.deleteAll();
|
||||
|
||||
populatePeople();
|
||||
populateOrders();
|
||||
populateAuthorsAndBooks();
|
||||
}
|
||||
|
||||
private void populateAuthorsAndBooks() {
|
||||
|
||||
Author ollie = new Author("Ollie");
|
||||
Author mark = new Author("Mark");
|
||||
Author michael = new Author("Michael");
|
||||
Author david = new Author("David");
|
||||
Author john = new Author("John");
|
||||
Author thomas = new Author("Thomas");
|
||||
|
||||
Iterable<Author> authors = this.authors.save(Arrays.asList(ollie, mark, michael, david, john, thomas));
|
||||
|
||||
books.save(new Book("1449323952", "Spring Data", authors));
|
||||
books.save(new Book("1449323953", "Spring Data (Second Edition)", authors));
|
||||
}
|
||||
|
||||
private void populateOrders() {
|
||||
|
||||
Person person = people.findAll().iterator().next();
|
||||
|
||||
Order order = new Order(person);
|
||||
order.add(new LineItem("Java Chip"));
|
||||
orders.save(order);
|
||||
}
|
||||
|
||||
private void populatePeople() {
|
||||
|
||||
Person billyBob = people.save(new Person("Billy Bob", "Thornton"));
|
||||
|
||||
Person john = new Person("John", "Doe");
|
||||
Person jane = new Person("Jane", "Doe");
|
||||
john.addSibling(jane);
|
||||
john.setFather(billyBob);
|
||||
jane.addSibling(john);
|
||||
jane.setFather(billyBob);
|
||||
|
||||
people.save(Arrays.asList(john, jane));
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.jpa;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
IN_STORE, TAKE_AWAY;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.jpa;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-463
|
||||
*/
|
||||
@Entity
|
||||
public class User {
|
||||
|
||||
private @Id @GeneratedValue Long id;
|
||||
private String name;
|
||||
private @JsonIgnore String password;
|
||||
|
||||
private String[] roles;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String[] getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(String... roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.jpa;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Elen - Sink like a stone (Elen)
|
||||
*/
|
||||
public interface UserExcerpt {
|
||||
|
||||
UserExcerpt getFather();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.jpa;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-463
|
||||
*/
|
||||
interface UserRepository extends CrudRepository<User, Long> {}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.jpa.groovy;
|
||||
|
||||
import groovy.lang.GroovyObject;
|
||||
import groovy.lang.MetaClass;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* Simulates a Groovy domain object by extending {@link GroovyObject}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
@Entity
|
||||
public class SimulatedGroovyDomainClass implements GroovyObject {
|
||||
|
||||
private @Id @GeneratedValue Long id;
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//
|
||||
// The following fields don't actually have to be implemented since the test cases don't
|
||||
// make any Groovy calls. This just simulates the structure of a Groovy object to
|
||||
// verify proper handling.
|
||||
//
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(String s, Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String s, Object o) {}
|
||||
|
||||
@Override
|
||||
public MetaClass getMetaClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetaClass(MetaClass metaClass) {}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.jpa.groovy;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Simulates a repository built on a Groovy domain object.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
public interface SimulatedGroovyDomainClassRepository extends CrudRepository<SimulatedGroovyDomainClass, Long> {}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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,11 +30,11 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
@@ -59,7 +59,7 @@ public class DomainObjectReaderUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
KeyValueMappingContext mappingContext = new KeyValueMappingContext();
|
||||
mappingContext.getPersistentEntity(SampleUser.class);
|
||||
mappingContext.getPersistentEntity(Person.class);
|
||||
mappingContext.getPersistentEntity(TypeWithGenericMap.class);
|
||||
@@ -68,8 +68,7 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
PersistentEntities entities = new PersistentEntities(Collections.singleton(mappingContext));
|
||||
|
||||
this.reader = new DomainObjectReader(entities,
|
||||
new AssociationLinks(mappings, mock(RepositoryRestConfiguration.class)));
|
||||
this.reader = new DomainObjectReader(entities, new Associations(mappings, mock(RepositoryRestConfiguration.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.jpa.Order;
|
||||
import org.springframework.data.rest.webmvc.jpa.OrderRepository;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.jpa.PersonRepository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link Jackson2DatatypeHelper}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { RepositoryTestsConfig.class, RepositoryRestMvcConfiguration.class })
|
||||
@Transactional
|
||||
public class Jackson2DatatypeHelperIntegrationTests {
|
||||
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired ObjectMapper objectMapper;
|
||||
|
||||
@Autowired PersonRepository people;
|
||||
@Autowired OrderRepository orders;
|
||||
@Autowired EntityManager em;
|
||||
|
||||
Order order;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.order = orders.save(new Order(people.save(new Person("Dave", "Matthews"))));
|
||||
|
||||
// Reset JPA to make sure the query returns a result with proxy references
|
||||
em.flush();
|
||||
em.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-500
|
||||
*/
|
||||
@Test
|
||||
public void configuresHIbernate4ModuleToLoadLazyLoadingProxies() throws Exception {
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(Order.class);
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("creator");
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(orders.findOne(this.order.getId()));
|
||||
|
||||
assertThat(objectMapper.writeValueAsString(accessor.getProperty(property)), is(not("null")));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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,10 +22,10 @@ import java.io.IOException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -51,7 +51,7 @@ public class JacksonMetadataUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.context = new MongoMappingContext();
|
||||
this.context = new KeyValueMappingContext();
|
||||
|
||||
this.mapper = new ObjectMapper();
|
||||
this.mapper.disable(MapperFeature.INFER_PROPERTY_MUTATORS);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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,9 +30,9 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
@@ -44,7 +44,7 @@ import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.AssociationUriResolvingDeserializerModifier;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.LookupObjectSerializer;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
@@ -66,7 +66,7 @@ import com.jayway.jsonpath.JsonPath;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PersistentEntityJackson2ModuleUnitTests {
|
||||
|
||||
@Mock AssociationLinks associations;
|
||||
@Mock Associations associations;
|
||||
@Mock UriToEntityConverter converter;
|
||||
@Mock EntityLinks entityLinks;
|
||||
@Mock ResourceMappings mappings;
|
||||
@@ -78,7 +78,7 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
KeyValueMappingContext mappingContext = new KeyValueMappingContext();
|
||||
mappingContext.getPersistentEntity(Sample.class);
|
||||
mappingContext.getPersistentEntity(SampleWithAdditionalGetters.class);
|
||||
mappingContext.getPersistentEntity(PersistentEntityJackson2ModuleUnitTests.PetOwner.class);
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-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.webmvc.json;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.context.support.StaticMessageSource;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.jpa.LineItem;
|
||||
import org.springframework.data.rest.webmvc.jpa.Order;
|
||||
import org.springframework.data.rest.webmvc.jpa.OrderRepository;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.jpa.PersonRepository;
|
||||
import org.springframework.data.rest.webmvc.jpa.PersonSummary;
|
||||
import org.springframework.data.rest.webmvc.jpa.UserExcerpt;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Address;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User.Gender;
|
||||
import org.springframework.data.rest.webmvc.util.TestUtils;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.core.EmbeddedWrapper;
|
||||
import org.springframework.hateoas.core.EmbeddedWrappers;
|
||||
import org.springframework.hateoas.hal.HalLinkDiscoverer;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Integration tests for entity (de)serialization.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { RepositoryTestsConfig.class, PersistentEntitySerializationTests.TestConfig.class })
|
||||
@Transactional
|
||||
public class PersistentEntitySerializationTests {
|
||||
|
||||
private static final String PERSON_JSON_IN = "{\"firstName\": \"John\",\"lastName\": \"Doe\"}";
|
||||
|
||||
@Autowired ObjectMapper mapper;
|
||||
@Autowired Repositories repositories;
|
||||
@Autowired PersonRepository people;
|
||||
@Autowired OrderRepository orders;
|
||||
|
||||
@Configuration
|
||||
static class TestConfig extends RepositoryTestsConfig {
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ObjectMapper objectMapper() {
|
||||
|
||||
ObjectMapper objectMapper = super.objectMapper();
|
||||
objectMapper.registerModule(
|
||||
new JacksonSerializers(new EnumTranslator(new MessageSourceAccessor(new StaticMessageSource()))));
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
LinkDiscoverer linkDiscoverer;
|
||||
ProjectionFactory projectionFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
RequestContextHolder.setRequestAttributes(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
|
||||
this.linkDiscoverer = new HalLinkDiscoverer();
|
||||
this.projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializesPersonEntity() throws IOException {
|
||||
|
||||
Person p = mapper.readValue(PERSON_JSON_IN, Person.class);
|
||||
|
||||
assertThat(p.getFirstName(), is("John"));
|
||||
assertThat(p.getLastName(), is("Doe"));
|
||||
assertThat(p.getSiblings(), is(Collections.EMPTY_LIST));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-238
|
||||
*/
|
||||
@Test
|
||||
public void deserializePersonWithLinks() throws IOException {
|
||||
|
||||
String bilbo = "{\n" + " \"_links\" : {\n" + " \"self\" : {\n"
|
||||
+ " \"href\" : \"http://localhost/people/4\"\n" + " },\n" + " \"siblings\" : {\n"
|
||||
+ " \"href\" : \"http://localhost/people/4/siblings\"\n" + " },\n" + " \"father\" : {\n"
|
||||
+ " \"href\" : \"http://localhost/people/4/father\"\n" + " }\n" + " },\n"
|
||||
+ " \"firstName\" : \"Bilbo\",\n" + " \"lastName\" : \"Baggins\",\n"
|
||||
+ " \"created\" : \"2014-01-31T21:07:45.574+0000\"\n" + "}\n";
|
||||
|
||||
Person p = mapper.readValue(bilbo, Person.class);
|
||||
assertThat(p.getFirstName(), equalTo("Bilbo"));
|
||||
assertThat(p.getLastName(), equalTo("Baggins"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-238
|
||||
*/
|
||||
@Test
|
||||
public void serializesPersonEntity() throws IOException, InterruptedException {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity(Person.class);
|
||||
Person person = people.save(new Person("John", "Doe"));
|
||||
|
||||
PersistentEntityResource resource = PersistentEntityResource.build(person, persistentEntity).//
|
||||
withLink(new Link("/person/" + person.getId())).build();
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
mapper.writeValue(writer, resource);
|
||||
|
||||
String s = writer.toString();
|
||||
|
||||
Link fatherLink = linkDiscoverer.findLinkWithRel("father", s);
|
||||
assertThat(fatherLink.getHref(), endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString()));
|
||||
|
||||
Link siblingLink = linkDiscoverer.findLinkWithRel("siblings", s);
|
||||
assertThat(siblingLink.getHref(), endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-248
|
||||
*/
|
||||
@Test
|
||||
public void deserializesPersonWithLinkToOtherPersonCorrectly() throws Exception {
|
||||
|
||||
Person father = people.save(new Person("John", "Doe"));
|
||||
|
||||
String child = String.format("{ \"firstName\" : \"Bilbo\", \"father\" : \"/persons/%s\"}", father.getId());
|
||||
Person result = mapper.readValue(child, Person.class);
|
||||
|
||||
assertThat(result.getFather(), is(father));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-248
|
||||
*/
|
||||
@Test
|
||||
public void deserializesPersonWithLinkToOtherPersonsCorrectly() throws Exception {
|
||||
|
||||
Person firstSibling = people.save(new Person("John", "Doe"));
|
||||
Person secondSibling = people.save(new Person("Dave", "Doe"));
|
||||
|
||||
String child = String.format("{ \"firstName\" : \"Bilbo\", \"siblings\" : [\"/persons/%s\", \"/persons/%s\"]}",
|
||||
firstSibling.getId(), secondSibling.getId());
|
||||
Person result = mapper.readValue(child, Person.class);
|
||||
|
||||
assertThat(result.getSiblings(), hasItems(firstSibling, secondSibling));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-248
|
||||
*/
|
||||
@Test
|
||||
public void deserializesEmbeddedAssociationsCorrectly() throws Exception {
|
||||
|
||||
String content = TestUtils.readFileFromClasspath("order.json");
|
||||
|
||||
Order order = mapper.readValue(content, Order.class);
|
||||
assertThat(order.getLineItems(), hasSize(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-250
|
||||
*/
|
||||
@Test
|
||||
public void serializesEmbeddedReferencesCorrectly() throws Exception {
|
||||
|
||||
User user = new User();
|
||||
user.address = new Address();
|
||||
user.address.street = "Street";
|
||||
|
||||
PersistentEntityResource userResource = PersistentEntityResource.//
|
||||
build(user, repositories.getPersistentEntity(User.class)).//
|
||||
withLink(new Link("/users/1")).//
|
||||
build();
|
||||
|
||||
PagedResources<PersistentEntityResource> persistentEntityResource = new PagedResources<PersistentEntityResource>(
|
||||
Arrays.asList(userResource), new PageMetadata(1, 0, 10));
|
||||
|
||||
String result = mapper.writeValueAsString(persistentEntityResource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_embedded.users[*].address"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-250
|
||||
*/
|
||||
@Test
|
||||
public void serializesReferencesWithinPagedResourceCorrectly() throws Exception {
|
||||
|
||||
Person creator = new Person("Dave", "Matthews");
|
||||
|
||||
Order order = new Order(creator);
|
||||
order.add(new LineItem("first"));
|
||||
order.add(new LineItem("second"));
|
||||
|
||||
PersistentEntityResource orderResource = PersistentEntityResource.//
|
||||
build(order, repositories.getPersistentEntity(Order.class)).//
|
||||
withLink(new Link("/orders/1")).//
|
||||
build();
|
||||
|
||||
PagedResources<PersistentEntityResource> persistentEntityResource = new PagedResources<PersistentEntityResource>(
|
||||
Arrays.asList(orderResource), new PageMetadata(1, 0, 10));
|
||||
|
||||
String result = mapper.writeValueAsString(persistentEntityResource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_embedded.orders[*].lineItems"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-521
|
||||
*/
|
||||
@Test
|
||||
public void serializesLinksForExcerpts() throws Exception {
|
||||
|
||||
Person dave = new Person("Dave", "Matthews");
|
||||
dave.setId(1L);
|
||||
|
||||
Person oliver = new Person("Oliver August", "Matthews");
|
||||
oliver.setId(2L);
|
||||
oliver.setFather(dave);
|
||||
|
||||
UserExcerpt daveExcerpt = projectionFactory.createProjection(UserExcerpt.class, dave);
|
||||
EmbeddedWrapper wrapper = new EmbeddedWrappers(false).wrap(daveExcerpt, "father");
|
||||
|
||||
PersistentEntityResource resource = PersistentEntityResource.//
|
||||
build(oliver, repositories.getPersistentEntity(Person.class)).//
|
||||
withEmbedded(Arrays.asList(wrapper)).//
|
||||
build();
|
||||
|
||||
String result = mapper.writeValueAsString(resource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_embedded.father[*]._links.self"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-521
|
||||
*/
|
||||
@Test
|
||||
public void rendersAdditionalLinksRegisteredWithResource() throws Exception {
|
||||
|
||||
Person dave = new Person("Dave", "Matthews");
|
||||
|
||||
PersistentEntityResource resource = PersistentEntityResource.//
|
||||
build(dave, repositories.getPersistentEntity(Person.class)).//
|
||||
withLink(new Link("/people/1")).//
|
||||
withLink(new Link("/aditional", "processed")).//
|
||||
build();
|
||||
|
||||
String result = mapper.writeValueAsString(resource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_links.processed"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-654
|
||||
*/
|
||||
@Test
|
||||
public void deserializesTranslatedEnumProperty() throws Exception {
|
||||
assertThat(mapper.readValue("{ \"gender\" : \"Male\" }", User.class).gender, is(Gender.MALE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-697
|
||||
*/
|
||||
@Test
|
||||
public void rendersProjectionWithinSimpleResourceCorrectly() throws Exception {
|
||||
|
||||
Person person = new Person("Dave", "Matthews");
|
||||
person.setId(1L);
|
||||
|
||||
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
|
||||
PersonSummary projection = factory.createProjection(PersonSummary.class, person);
|
||||
|
||||
String result = mapper.writeValueAsString(new Resource<PersonSummary>(projection));
|
||||
|
||||
assertThat(JsonPath.read(result, "$._links.self"), is(notNullValue()));
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.config.JsonSchemaFormat;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.TestMvcClient;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverter.ValueTypeSchemaPropertyCustomizerFactory;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverterUnitTests.TestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Profile;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User.EmailAddress;
|
||||
import org.springframework.data.rest.webmvc.mongodb.User.TypeWithPattern;
|
||||
import org.springframework.data.rest.webmvc.mongodb.groovy.SimulatedGroovyDomainClass;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { MongoDbRepositoryConfig.class, TestConfiguration.class })
|
||||
public class PersistentEntityToJsonSchemaConverterUnitTests {
|
||||
|
||||
@Autowired @Qualifier("resourceDescriptionMessageSourceAccessor") MessageSourceAccessor accessor;
|
||||
@Autowired RepositoryRestConfiguration configuration;
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired @Qualifier("objectMapper") ObjectMapper objectMapper;
|
||||
@Autowired AssociationLinks associations;
|
||||
|
||||
@Configuration
|
||||
@Import(RepositoryRestMvcConfiguration.class)
|
||||
static class TestConfiguration extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
|
||||
config.getMetadataConfiguration().registerJsonSchemaFormat(JsonSchemaFormat.EMAIL, EmailAddress.class);
|
||||
config.getMetadataConfiguration().registerFormattingPatternFor("[A-Z]+", TypeWithPattern.class);
|
||||
|
||||
config.exposeIdsFor(Profile.class);
|
||||
}
|
||||
}
|
||||
|
||||
PersistentEntityToJsonSchemaConverter converter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
TestMvcClient.initWebTest();
|
||||
|
||||
ValueTypeSchemaPropertyCustomizerFactory customizerFactory = mock(ValueTypeSchemaPropertyCustomizerFactory.class);
|
||||
|
||||
converter = new PersistentEntityToJsonSchemaConverter(entities, associations, accessor, objectMapper, configuration,
|
||||
customizerFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-631, DATAREST-632
|
||||
*/
|
||||
@Test
|
||||
public void fulfillsConstraintsForProfile() {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.id", is(notNullValue()), "Has descriptor for id property"));
|
||||
constraints.add(new Constraint("$.description", is("Profile description"), "Adds description to schema root"));
|
||||
constraints.add(new Constraint("$.properties.renamed", is(notNullValue()), "Has descriptor for renamed property"));
|
||||
constraints.add(
|
||||
new Constraint("$.properties.aliased", is(nullValue()), "No descriptor for original name of renamed property"));
|
||||
|
||||
assertConstraints(Profile.class, constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-632
|
||||
*/
|
||||
@Test
|
||||
public void fulfillsConstraintsForUser() throws Exception {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.id", is(nullValue()), "Does NOT have descriptor for id property"));
|
||||
constraints.add(new Constraint("$.properties.firstname.type", is("string"), "Exposes firstname as String"));
|
||||
constraints
|
||||
.add(new Constraint("$.definitions.address", is(notNullValue()), "Exposes nested objects as definitions."));
|
||||
constraints.add(new Constraint("$.definitions.address.type", is("object"), "Nested entity is of type 'object'"));
|
||||
constraints.add(
|
||||
new Constraint("$.definitions.address.properties.zipCode", is(notNullValue()), "Exposes nested properties"));
|
||||
constraints.add(
|
||||
new Constraint("$.definitions.address.requiredProperties[0]", is("zipCode"), "Lists nested required property"));
|
||||
constraints.add(new Constraint("$.properties.gender.type", is("string"), "Enums are strings."));
|
||||
constraints.add(new Constraint("$.properties.gender.enum", is(notNullValue()), "Exposes enum values."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.jodaDateTime.format", is("date-time"), "Exposes JodaTime dates in format."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.java8DateTime.format", is("date-time"), "Exposes Java 8 dates in format."));
|
||||
constraints.add(new Constraint("$.properties.nicknames.type", is("array"), "Exposes collection of simple types."));
|
||||
constraints.add(new Constraint("$.properties.nicknames.items.type", is("string"),
|
||||
"Exposes element type of collection of simple types."));
|
||||
constraints.add(new Constraint("$.properties.email.format", is("email"), "Uses manually configured format."));
|
||||
constraints.add(new Constraint("$.properties.email.type", is("string"), "Treats types with format as String."));
|
||||
|
||||
constraints.add(
|
||||
new Constraint("$.properties.shippingAddresses.type", is("array"), "Exposes collection of complex types."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.shippingAddresses.uniqueItems", is(true), "Exposes uniqueness for Sets."));
|
||||
constraints.add(new Constraint("$.properties.shippingAddresses.items['$ref']", is("#/definitions/address"),
|
||||
"References definition of complex element type."));
|
||||
|
||||
// DATAREST-531
|
||||
constraints.add(new Constraint("$.properties.email.readOnly", is(true), "Email is read-only property"));
|
||||
|
||||
// DATAREST-644
|
||||
constraints.add(new Constraint("$.properties.shippingAddresses.title", is("Shipping addresses"),
|
||||
"Defaults titles correctly (split at camel case)"));
|
||||
|
||||
// DATAREST-665
|
||||
constraints.add(new Constraint("$.properties.address.title", is("Adresse"), "I18n from simple property"));
|
||||
constraints.add(new Constraint("$.properties.gender.title", is("Geschlecht"), "I18n from property on local type"));
|
||||
constraints.add(
|
||||
new Constraint("$.properties.firstname.title", is("Vorname"), "I18n from property on fully-qualified type"));
|
||||
|
||||
// DATAREST-690
|
||||
constraints.add(new Constraint("$.properties.colleagues.items", is(nullValue()),
|
||||
"Items must not appear for collection associations."));
|
||||
|
||||
assertConstraints(User.class, constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
@Test
|
||||
public void handlesGroovyDomainObjects() {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.name", is(notNullValue()), "Has descriptor for name property"));
|
||||
|
||||
assertConstraints(SimulatedGroovyDomainClass.class, constraints);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertConstraints(Class<?> type, Iterable<Constraint> constraints) {
|
||||
|
||||
String writeSchemaFor = writeSchemaFor(type);
|
||||
|
||||
for (Constraint constraint : constraints) {
|
||||
|
||||
try {
|
||||
assertThat(constraint.description, JsonPath.read(writeSchemaFor, constraint.selector), constraint.matcher);
|
||||
} catch (RuntimeException e) {
|
||||
assertThat(e, constraint.matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String writeSchemaFor(Class<?> type) {
|
||||
|
||||
try {
|
||||
return objectMapper.writeValueAsString(converter.convert(type));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class Constraint {
|
||||
|
||||
String selector;
|
||||
Matcher matcher;
|
||||
String description;
|
||||
|
||||
public Constraint(String selector, Matcher matcher, String description) {
|
||||
this.selector = selector;
|
||||
this.matcher = matcher;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.repository.support.DefaultRepositoryInvokerFactory;
|
||||
import org.springframework.data.repository.support.DomainClassConverter;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
import org.springframework.data.rest.core.config.EnumTranslationConfiguration;
|
||||
import org.springframework.data.rest.core.config.MetadataConfiguration;
|
||||
import org.springframework.data.rest.core.config.ProjectionDefinitionConfiguration;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.RepositoryResourceMappings;
|
||||
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
|
||||
import org.springframework.data.rest.webmvc.ResourceProcessorInvoker;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.Person;
|
||||
import org.springframework.data.rest.webmvc.jpa.PersonRepository;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.LookupObjectSerializer;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
|
||||
import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConverter;
|
||||
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
|
||||
import org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
import org.springframework.hateoas.hal.Jackson2HalModule;
|
||||
import org.springframework.plugin.core.OrderAwarePluginRegistry;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
@Import({ JpaRepositoryConfig.class, MongoDbRepositoryConfig.class })
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RepositoryTestsConfig {
|
||||
|
||||
@Autowired ApplicationContext appCtx;
|
||||
@Autowired(required = false) List<MappingContext<?, ?>> mappingContexts = Collections.emptyList();
|
||||
|
||||
@Bean
|
||||
public Repositories repositories() {
|
||||
return new Repositories(appCtx);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RepositoryRestConfiguration config() {
|
||||
RepositoryRestConfiguration config = new RepositoryRestConfiguration(new ProjectionDefinitionConfiguration(),
|
||||
new MetadataConfiguration(), mock(EnumTranslationConfiguration.class));
|
||||
|
||||
config.setResourceMappingForDomainType(Person.class).setRel("person");
|
||||
|
||||
config.setResourceMappingForRepository(PersonRepository.class).setRel("people").setPath("people")
|
||||
.addResourceMappingFor("findByFirstName").setRel("firstname").setPath("firstname");
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultFormattingConversionService defaultConversionService() {
|
||||
|
||||
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
|
||||
|
||||
DomainClassConverter<FormattingConversionService> converter = new DomainClassConverter<FormattingConversionService>(
|
||||
conversionService);
|
||||
converter.setApplicationContext(appCtx);
|
||||
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersistentEntities persistentEntities() {
|
||||
return new PersistentEntities(mappingContexts);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Module persistentEntityModule() {
|
||||
|
||||
RepositoryResourceMappings mappings = new RepositoryResourceMappings(repositories(), persistentEntities(),
|
||||
config().getRepositoryDetectionStrategy());
|
||||
EntityLinks entityLinks = new RepositoryEntityLinks(repositories(), mappings, config(),
|
||||
mock(PagingAndSortingTemplateVariables.class),
|
||||
OrderAwarePluginRegistry.<Class<?>, BackendIdConverter> create(Arrays.asList(DefaultIdConverter.INSTANCE)));
|
||||
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(persistentEntities(), entityLinks,
|
||||
Collections.<EntityLookup<?>> emptyList());
|
||||
|
||||
DefaultRepositoryInvokerFactory invokerFactory = new DefaultRepositoryInvokerFactory(repositories());
|
||||
UriToEntityConverter uriToEntityConverter = new UriToEntityConverter(persistentEntities(), invokerFactory,
|
||||
repositories());
|
||||
|
||||
AssociationLinks associations = new AssociationLinks(mappings, config());
|
||||
LinkCollector collector = new LinkCollector(persistentEntities(), selfLinkProvider, associations);
|
||||
|
||||
NestedEntitySerializer nestedEntitySerializer = new NestedEntitySerializer(persistentEntities(),
|
||||
new EmbeddedResourcesAssembler(persistentEntities(), associations, mock(ExcerptProjector.class)),
|
||||
new ResourceProcessorInvoker(Collections.<ResourceProcessor<?>> emptyList()));
|
||||
|
||||
return new PersistentEntityJackson2Module(associations, persistentEntities(), uriToEntityConverter, collector,
|
||||
invokerFactory, nestedEntitySerializer, mock(LookupObjectSerializer.class));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
|
||||
RelProvider relProvider = new EvoInflectorRelProvider();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
mapper.registerModule(new Jackson2HalModule());
|
||||
mapper.registerModule(persistentEntityModule());
|
||||
mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, null, null));
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.setSerializationInclusion(Include.NON_EMPTY);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2016 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.mapping;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
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.annotation.Reference;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AssociationsUnitTests {
|
||||
|
||||
@Mock RepositoryRestConfiguration configuration;
|
||||
|
||||
@Mock PersistentEntity<?, ?> entity;
|
||||
@Mock PersistentProperty<?> property;
|
||||
|
||||
Associations associations;
|
||||
|
||||
KeyValueMappingContext mappingContext;
|
||||
ResourceMappings mappings;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mappingContext = new KeyValueMappingContext();
|
||||
this.mappingContext.getPersistentEntity(Root.class);
|
||||
|
||||
this.mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(mappingContext)));
|
||||
|
||||
this.associations = new Associations(mappings, configuration);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullMappings() {
|
||||
new Associations(null, configuration);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullConfiguration() {
|
||||
new Associations(mappings, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlesNullPropertyForLookupTypeCheck() {
|
||||
assertThat(associations.isLookupType(null), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsLookupTypeCheckToConfiguration() {
|
||||
|
||||
doReturn(Root.class).when(property).getActualType();
|
||||
assertThat(associations.isLookupType(property), is(false));
|
||||
|
||||
doReturn(true).when(configuration).isLookupType(Root.class);
|
||||
assertThat(associations.isLookupType(property), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsIdExposureCheckToConfiguration() {
|
||||
|
||||
doReturn(Root.class).when(entity).getType();
|
||||
assertThat(associations.isIdExposed(entity), is(false));
|
||||
|
||||
doReturn(true).when(configuration).isIdExposedFor(Root.class);
|
||||
assertThat(associations.isIdExposed(entity), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposesConfiguredMapping() {
|
||||
assertThat(associations.getMappings(), is(mappings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsMetadataLookupToMappings() {
|
||||
assertThat(associations.getMetadataFor(Root.class), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsAssociationLinks() {
|
||||
|
||||
List<Link> links = associations.getLinksFor(getAssociation(Root.class, "relatedAndExported"), new Path(""));
|
||||
|
||||
assertThat(links, hasSize(1));
|
||||
assertThat(links, hasItem(new Link("/relatedAndExported", "relatedAndExported")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotCreateAssociationLinkIfTargetIsNotExported() {
|
||||
|
||||
List<Link> links = associations.getLinksFor(getAssociation(Root.class, "relatedButNotExported"), new Path(""));
|
||||
|
||||
assertThat(links, hasSize(0));
|
||||
}
|
||||
|
||||
private Association<? extends PersistentProperty<?>> getAssociation(Class<?> type, String name) {
|
||||
|
||||
KeyValuePersistentEntity<?> rootEntity = mappingContext.getPersistentEntity(type);
|
||||
return new Association<KeyValuePersistentProperty>(rootEntity.getPersistentProperty(name), null);
|
||||
}
|
||||
|
||||
static class Root {
|
||||
@Reference RelatedAndExported relatedAndExported;
|
||||
@Reference RelatedButNotExported relatedButNotExported;
|
||||
}
|
||||
|
||||
@RestResource(exported = true)
|
||||
static class RelatedAndExported {}
|
||||
|
||||
static class RelatedButNotExported {}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.mongodb;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Address {
|
||||
|
||||
public String street;
|
||||
public @JsonProperty(required = true) String zipCode;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-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.webmvc.mongodb;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||
import org.springframework.data.mongodb.config.EnableMongoAuditing;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableMongoAuditing
|
||||
public class MongoDbRepositoryConfig extends AbstractMongoConfiguration {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#getDatabaseName()
|
||||
*/
|
||||
@Override
|
||||
protected String getDatabaseName() {
|
||||
return "spring-data-rest-sample";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#getMappingBasePackage()
|
||||
*/
|
||||
@Override
|
||||
protected String getMappingBasePackage() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#mongo()
|
||||
*/
|
||||
@Override
|
||||
public Mongo mongo() throws Exception {
|
||||
return new MongoClient();
|
||||
}
|
||||
}
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.mongodb;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.http.HttpHeaders.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.CommonWebTests;
|
||||
import org.springframework.data.rest.webmvc.RestMediaTypes;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Integration tests for MongoDB repositories.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
|
||||
public class MongoWebTests extends CommonWebTests {
|
||||
|
||||
@Autowired ProfileRepository repository;
|
||||
@Autowired UserRepository userRepository;
|
||||
@Autowired RepositoryEntityLinks entityLinks;
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Before
|
||||
public void populateProfiles() {
|
||||
|
||||
mapper.setSerializationInclusion(Include.NON_NULL);
|
||||
|
||||
Profile twitter = new Profile();
|
||||
twitter.setPerson(1L);
|
||||
twitter.setType("Twitter");
|
||||
|
||||
Profile linkedIn = new Profile();
|
||||
linkedIn.setPerson(1L);
|
||||
linkedIn.setType("LinkedIn");
|
||||
|
||||
repository.save(Arrays.asList(twitter, linkedIn));
|
||||
|
||||
Address address = new Address();
|
||||
address.street = "ETagDoesntMatchExceptionUnitTests";
|
||||
address.zipCode = "Bar";
|
||||
|
||||
User thomas = new User();
|
||||
thomas.firstname = "Thomas";
|
||||
thomas.lastname = "Darimont";
|
||||
thomas.address = address;
|
||||
|
||||
userRepository.save(thomas);
|
||||
|
||||
User oliver = new User();
|
||||
oliver.firstname = "Oliver";
|
||||
oliver.lastname = "Gierke";
|
||||
oliver.address = address;
|
||||
oliver.colleagues = Arrays.asList(thomas);
|
||||
userRepository.save(oliver);
|
||||
|
||||
thomas.colleagues = Arrays.asList(oliver);
|
||||
userRepository.save(thomas);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
repository.deleteAll();
|
||||
userRepository.deleteAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels()
|
||||
*/
|
||||
@Override
|
||||
protected Iterable<String> expectedRootLinkRels() {
|
||||
return Arrays.asList("profiles", "users");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foo() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profiles");
|
||||
client.follow(profileLink).//
|
||||
andExpect(jsonPath("$._embedded.profiles").value(hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rendersEmbeddedDocuments() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
client.follow(userLink).//
|
||||
andExpect(jsonPath("$.address.zipCode").value(is(notNullValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-247
|
||||
*/
|
||||
@Test
|
||||
public void executeQueryMethodWithPrimitiveReturnType() throws Exception {
|
||||
|
||||
Link profiles = client.discoverUnique("profiles");
|
||||
Link profileSearches = client.discoverUnique(profiles, "search");
|
||||
Link countByTypeLink = client.discoverUnique(profileSearches, "countByType");
|
||||
|
||||
assertThat(countByTypeLink.isTemplated(), is(true));
|
||||
assertThat(countByTypeLink.getVariableNames(), hasItem("type"));
|
||||
|
||||
MockHttpServletResponse response = client.request(countByTypeLink.expand("Twitter"));
|
||||
assertThat(response.getContentAsString(), is("1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testname() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
|
||||
MockHttpServletResponse response = patchAndGet(userLink,
|
||||
"{\"lastname\" : null, \"address\" : { \"zipCode\" : \"ZIP\"}}", MediaType.APPLICATION_JSON);
|
||||
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.lastname"), is(nullValue()));
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.address.zipCode"), is((Object) "ZIP"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testname2() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
|
||||
MockHttpServletResponse response = patchAndGet(userLink,
|
||||
"[{ \"op\": \"replace\", \"path\": \"/address/zipCode\", \"value\": \"ZIP\" },"
|
||||
// + "{ \"op\": \"replace\", \"path\": \"/lastname\", \"value\": null }]", //
|
||||
+ "{ \"op\": \"remove\", \"path\": \"/lastname\" }]", //
|
||||
RestMediaTypes.JSON_PATCH_JSON);
|
||||
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.lastname"), is(nullValue()));
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.address.zipCode"), is((Object) "ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-160
|
||||
*/
|
||||
@Test
|
||||
public void returnConflictWhenConcurrentlyEditingVersionedEntity() throws Exception {
|
||||
|
||||
Link receiptLink = client.discoverUnique("receipts");
|
||||
|
||||
Receipt receipt = new Receipt();
|
||||
receipt.amount = new BigDecimal(50);
|
||||
receipt.saleItem = "Springy Tacos";
|
||||
|
||||
String stringReceipt = mapper.writeValueAsString(receipt);
|
||||
|
||||
MockHttpServletResponse createdReceipt = postAndGet(receiptLink, stringReceipt, MediaType.APPLICATION_JSON);
|
||||
Link tacosLink = client.assertHasLinkWithRel("self", createdReceipt);
|
||||
assertJsonPathEquals("$.saleItem", "Springy Tacos", createdReceipt);
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(tacosLink.getHref());
|
||||
String concurrencyTag = createdReceipt.getHeader("ETag");
|
||||
|
||||
mvc.perform(
|
||||
patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyBurritos\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, concurrencyTag)).andExpect(
|
||||
status().is2xxSuccessful());
|
||||
|
||||
mvc.perform(
|
||||
patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyTequila\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, concurrencyTag)).andExpect(
|
||||
status().isPreconditionFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-471
|
||||
*/
|
||||
@Test
|
||||
public void auditableResourceHasLastModifiedHeaderSet() throws Exception {
|
||||
|
||||
Profile profile = repository.findAll().iterator().next();
|
||||
|
||||
String header = mvc.perform(get("/profiles/{id}", profile.getId())).//
|
||||
andReturn().getResponse().getHeader("Last-Modified");
|
||||
|
||||
assertThat(header, not(isEmptyOrNullString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-482
|
||||
*/
|
||||
@Test
|
||||
public void putDoesNotRemoveAssociations() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink));
|
||||
|
||||
// Expect a user returned as colleague
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(jsonPath("$._embedded.users").exists());
|
||||
|
||||
User oliver = new User();
|
||||
oliver.firstname = "Oliver";
|
||||
oliver.lastname = "Gierke";
|
||||
|
||||
putAndGet(userLink, mapper.writeValueAsString(oliver), MediaType.APPLICATION_JSON);
|
||||
|
||||
// Expect colleague still present but address has been wiped
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(jsonPath("$._embedded.users").exists()).//
|
||||
andExpect(jsonPath("$.embedded.users[0].address").doesNotExist());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-482
|
||||
*/
|
||||
@Test
|
||||
public void emptiesAssociationForEmptyUriList() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink));
|
||||
|
||||
putAndGet(colleaguesLink, "", MediaType.parseMediaType("text/uri-list"));
|
||||
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(jsonPath("$").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-491
|
||||
*/
|
||||
@Test
|
||||
public void updatesMapPropertyCorrectly() throws Exception {
|
||||
|
||||
Link profilesLink = client.discoverUnique("profiles");
|
||||
Link profileLink = assertHasContentLinkWithRel("self", client.request(profilesLink));
|
||||
|
||||
Profile profile = new Profile();
|
||||
profile.setMetadata(Collections.singletonMap("Key", "Value"));
|
||||
|
||||
putAndGet(profileLink, mapper.writeValueAsString(profile), MediaType.APPLICATION_JSON);
|
||||
|
||||
client.follow(profileLink).andExpect(jsonPath("$.metadata.Key").value("Value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-506
|
||||
*/
|
||||
@Test
|
||||
public void supportsConditionalGetsOnItemResource() throws Exception {
|
||||
|
||||
Receipt receipt = new Receipt();
|
||||
receipt.amount = new BigDecimal(50);
|
||||
receipt.saleItem = "Springy Tacos";
|
||||
|
||||
Link receiptsLink = client.discoverUnique("receipts");
|
||||
|
||||
MockHttpServletResponse response = postAndGet(receiptsLink, mapper.writeValueAsString(receipt),
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
Link receiptLink = client.getDiscoverer(response).findLinkWithRel("self", response.getContentAsString());
|
||||
|
||||
mvc.perform(get(receiptLink.getHref()).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).//
|
||||
andExpect(status().isNotModified()).//
|
||||
andExpect(header().string(ETAG, is(notNullValue())));
|
||||
|
||||
mvc.perform(get(receiptLink.getHref()).header(IF_NONE_MATCH, response.getHeader(ETAG))).//
|
||||
andExpect(status().isNotModified()).//
|
||||
andExpect(header().string(ETAG, is(notNullValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-511
|
||||
*/
|
||||
@Test
|
||||
public void invokesQueryResourceReturningAnOptional() throws Exception {
|
||||
|
||||
Profile profile = repository.findAll().iterator().next();
|
||||
|
||||
Link link = client.discoverUnique("profiles", "search", "findById");
|
||||
|
||||
mvc.perform(get(link.expand(profile.getId()).getHref())).//
|
||||
andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-517
|
||||
*/
|
||||
@Test
|
||||
public void returnsNotFoundIfQueryExecutionDoesNotReturnResult() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("profiles", "search", "findById");
|
||||
|
||||
mvc.perform(get(link.expand("").getHref())).//
|
||||
andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-712
|
||||
*/
|
||||
@Test
|
||||
public void invokesQueryMethodTakingAReferenceCorrectly() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("users", "search", "findByColleaguesContains");
|
||||
|
||||
User thomas = userRepository.findAll(QUser.user.firstname.eq("Thomas")).iterator().next();
|
||||
Link thomasUri = entityLinks.linkToSingleResource(User.class, thomas.id).expand();
|
||||
|
||||
String href = link.expand(thomasUri.getHref()).getHref();
|
||||
|
||||
mvc.perform(get(href)).andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-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.webmvc.mongodb;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Document
|
||||
public class Profile {
|
||||
|
||||
@Id private String id;
|
||||
private Long person;
|
||||
private @JsonProperty(required = true) String type;
|
||||
private @LastModifiedDate Date lastModifiedDate;
|
||||
private @JsonProperty("renamed") String aliased;
|
||||
private Map<String, String> metadata = new HashMap<String, String>();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Profile setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public Profile setPerson(Long person) {
|
||||
this.person = person;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Profile setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Date getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public String getAliased() {
|
||||
return aliased;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-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.webmvc.mongodb;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ProfileRepository extends PagingAndSortingRepository<Profile, String> {
|
||||
|
||||
List<Profile> findByType(String type);
|
||||
|
||||
/**
|
||||
* @see DATAREST-247
|
||||
*/
|
||||
long countByType(@Param("type") String type);
|
||||
|
||||
/**
|
||||
* @see DATAREST-511
|
||||
*/
|
||||
Optional<Profile> findById(@Param("id") String id);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.mongodb;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Pablo Lozano
|
||||
*/
|
||||
// tag::code[]
|
||||
@Document
|
||||
public class Receipt {
|
||||
|
||||
public @Id String id;
|
||||
public @Version Long version;
|
||||
public @LastModifiedDate Date date; // <1>
|
||||
|
||||
public String saleItem;
|
||||
public BigDecimal amount;
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.mongodb;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Receipt}s.
|
||||
*
|
||||
* @author Pablo Lozano
|
||||
*/
|
||||
|
||||
public interface ReceiptRepository extends CrudRepository<Receipt, String> {
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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.webmvc.mongodb;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Document
|
||||
public class User {
|
||||
|
||||
public static enum Gender {
|
||||
MALE, FEMALE;
|
||||
}
|
||||
|
||||
public BigInteger id;
|
||||
public String firstname, lastname;
|
||||
public Address address;
|
||||
public Set<Address> shippingAddresses;
|
||||
public List<String> nicknames;
|
||||
public Gender gender;
|
||||
public @ReadOnlyProperty EmailAddress email;
|
||||
public LocalDateTime java8DateTime;
|
||||
public org.joda.time.LocalDateTime jodaDateTime;
|
||||
public TypeWithPattern pattern;
|
||||
public @DBRef(lazy = true) List<User> colleagues;
|
||||
|
||||
public static class EmailAddress {
|
||||
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* @param value
|
||||
*/
|
||||
public EmailAddress(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeWithPattern {}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.mongodb;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface UserRepository extends CrudRepository<User, BigInteger>, QueryDslPredicateExecutor<User> {
|
||||
|
||||
List<User> findByFirstname(String firstname);
|
||||
|
||||
List<User> findByColleaguesContains(@Param("colleagues") User colleague);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.webmvc.mongodb;
|
||||
|
||||
import org.springframework.data.rest.core.config.Projection;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Projection(types = User.class)
|
||||
public interface UserSummary {
|
||||
|
||||
String getFirstname();
|
||||
|
||||
String getLastname();
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.mongodb.groovy;
|
||||
|
||||
import groovy.lang.GroovyObject;
|
||||
import groovy.lang.MetaClass;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* Simulates a Groovy domain object by extending {@link GroovyObject}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
@Document
|
||||
public class SimulatedGroovyDomainClass implements GroovyObject {
|
||||
|
||||
private String id, name;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//
|
||||
// The following fields don't actually have to be implemented since the test cases don't
|
||||
// make any Groovy calls. This just simulates the structure of a Groovy object to
|
||||
// verify proper handling.
|
||||
//
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(String s, Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String s, Object o) {}
|
||||
|
||||
@Override
|
||||
public MetaClass getMetaClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetaClass(MetaClass metaClass) {}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.mongodb.groovy;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Simulates a repository built on a Groovy domain object.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
public interface SimulatedGroovyDomainClassRepository extends CrudRepository<SimulatedGroovyDomainClass, String> {}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.security;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "ORDERS")
|
||||
public class Order {
|
||||
|
||||
@Id @GeneratedValue//
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)//
|
||||
Person creator;
|
||||
|
||||
public Order(Person creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
protected Order() {
|
||||
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Person getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user