DATAREST-1008 - Adapt to API changes in Spring Data Commons, Java 8 upgrades and Mockito 2.7.
This commit is contained in:
@@ -16,12 +16,14 @@
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
@@ -31,6 +33,18 @@ public class ControllerUtils {
|
||||
|
||||
public static final Iterable<Resource<?>> EMPTY_RESOURCE_LIST = Collections.emptyList();
|
||||
|
||||
public static <R extends ResourceSupport> ResponseEntity<ResourceSupport> toResponseEntity(HttpStatus status,
|
||||
HttpHeaders headers, Optional<R> resource) {
|
||||
|
||||
HttpHeaders hdrs = new HttpHeaders();
|
||||
|
||||
if (headers != null) {
|
||||
hdrs.putAll(headers);
|
||||
}
|
||||
|
||||
return new ResponseEntity<ResourceSupport>(resource.orElse(null), hdrs, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a resource as a {@link ResourceEntity} and attach given headers and status.
|
||||
*
|
||||
@@ -43,13 +57,11 @@ public class ControllerUtils {
|
||||
public static <R extends ResourceSupport> ResponseEntity<ResourceSupport> toResponseEntity(HttpStatus status,
|
||||
HttpHeaders headers, R resource) {
|
||||
|
||||
HttpHeaders hdrs = new HttpHeaders();
|
||||
Assert.notNull(status, "Http status must not be null!");
|
||||
Assert.notNull(headers, "Http headers must not be null!");
|
||||
Assert.notNull(resource, "Payload must not be null!");
|
||||
|
||||
if (headers != null) {
|
||||
hdrs.putAll(headers);
|
||||
}
|
||||
|
||||
return new ResponseEntity<ResourceSupport>(resource, hdrs, status);
|
||||
return toResponseEntity(status, headers, Optional.of(resource));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +71,7 @@ public class ControllerUtils {
|
||||
* @return
|
||||
*/
|
||||
public static ResponseEntity<ResourceSupport> toEmptyResponse(HttpStatus status) {
|
||||
return toEmptyResponse(status, null);
|
||||
return toEmptyResponse(status, new HttpHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,6 +82,6 @@ public class ControllerUtils {
|
||||
* @return
|
||||
*/
|
||||
public static ResponseEntity<ResourceSupport> toEmptyResponse(HttpStatus status, HttpHeaders headers) {
|
||||
return toResponseEntity(status, headers, null);
|
||||
return toResponseEntity(status, headers, Optional.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -57,42 +56,31 @@ public class EmbeddedResourcesAssembler {
|
||||
|
||||
Assert.notNull(instance, "Entity instance must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(instance.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(instance.getClass());
|
||||
|
||||
final List<EmbeddedWrapper> associationProjections = new ArrayList<EmbeddedWrapper>();
|
||||
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance);
|
||||
final ResourceMetadata metadata = associations.getMetadataFor(entity.getType());
|
||||
|
||||
entity.doWithAssociations(new SimpleAssociationHandler() {
|
||||
entity.doWithAssociations((SimpleAssociationHandler) association -> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.SimpleAssociationHandler#doWithAssociation(org.springframework.data.mapping.Association)
|
||||
*/
|
||||
@Override
|
||||
public void doWithAssociation(Association<? extends PersistentProperty<?>> association) {
|
||||
PersistentProperty<?> property = association.getInverse();
|
||||
|
||||
PersistentProperty<?> property = association.getInverse();
|
||||
if (!associations.isLinkableAssociation(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!associations.isLinkableAssociation(property)) {
|
||||
return;
|
||||
}
|
||||
if (!projector.hasExcerptProjection(property.getActualType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!projector.hasExcerptProjection(property.getActualType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = accessor.getProperty(association.getInverse());
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
accessor.getProperty(association.getInverse()).ifPresent(it -> {
|
||||
|
||||
String rel = metadata.getMappingFor(property).getRel();
|
||||
|
||||
if (value instanceof Collection) {
|
||||
if (it instanceof Collection) {
|
||||
|
||||
Collection<?> collection = (Collection<?>) value;
|
||||
Collection<?> collection = (Collection<?>) it;
|
||||
|
||||
if (collection.isEmpty()) {
|
||||
return;
|
||||
@@ -109,9 +97,9 @@ public class EmbeddedResourcesAssembler {
|
||||
associationProjections.add(wrappers.wrap(nestedCollection, rel));
|
||||
|
||||
} else {
|
||||
associationProjections.add(wrappers.wrap(projector.projectExcerpt(value), rel));
|
||||
associationProjections.add(wrappers.wrap(projector.projectExcerpt(it), rel));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return associationProjections;
|
||||
|
||||
@@ -18,10 +18,15 @@ package org.springframework.data.rest.webmvc;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapper;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.convert.Jsr310Converters;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.rest.webmvc.support.ETag;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -38,6 +43,11 @@ import org.springframework.util.Assert;
|
||||
public class HttpHeadersPreparer {
|
||||
|
||||
private final @NonNull AuditableBeanWrapperFactory auditableBeanWrapperFactory;
|
||||
private final ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
{
|
||||
Jsr310Converters.getConvertersToRegister().forEach(conversionService::addConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default headers to be returned for the given {@link PersistentEntityResource}. Will set {@link ETag}
|
||||
@@ -46,8 +56,11 @@ public class HttpHeadersPreparer {
|
||||
* @param resource can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public HttpHeaders prepareHeaders(PersistentEntityResource resource) {
|
||||
return resource == null ? new HttpHeaders() : prepareHeaders(resource.getPersistentEntity(), resource.getContent());
|
||||
public HttpHeaders prepareHeaders(Optional<PersistentEntityResource> resource) {
|
||||
|
||||
return resource//
|
||||
.map(it -> prepareHeaders(it.getPersistentEntity(), it.getContent()))//
|
||||
.orElseGet(() -> new HttpHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,17 +77,7 @@ public class HttpHeadersPreparer {
|
||||
HttpHeaders headers = ETag.from(entity, value).addTo(new HttpHeaders());
|
||||
|
||||
// Add Last-Modified
|
||||
AuditableBeanWrapper wrapper = getAuditableBeanWrapper(value);
|
||||
|
||||
if (wrapper == null) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
Calendar lastModifiedDate = wrapper.getLastModifiedDate();
|
||||
|
||||
if (lastModifiedDate != null) {
|
||||
headers.setLastModified(lastModifiedDate.getTimeInMillis());
|
||||
}
|
||||
getLastModifiedInMilliseconds(value).ifPresent(it -> headers.setLastModified(it));
|
||||
|
||||
return headers;
|
||||
}
|
||||
@@ -95,10 +98,9 @@ public class HttpHeadersPreparer {
|
||||
return false;
|
||||
}
|
||||
|
||||
AuditableBeanWrapper wrapper = auditableBeanWrapperFactory.getBeanWrapperFor(source);
|
||||
long current = wrapper.getLastModifiedDate().getTimeInMillis() / 1000 * 1000;
|
||||
|
||||
return current <= headers.getIfModifiedSince();
|
||||
return getLastModifiedInMilliseconds(source)//
|
||||
.map(it -> it / 1000 * 1000 <= headers.getIfModifiedSince())//
|
||||
.orElse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +109,16 @@ public class HttpHeadersPreparer {
|
||||
* @param source can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private AuditableBeanWrapper getAuditableBeanWrapper(Object source) {
|
||||
private Optional<AuditableBeanWrapper> getAuditableBeanWrapper(Object source) {
|
||||
return auditableBeanWrapperFactory.getBeanWrapperFor(source);
|
||||
}
|
||||
|
||||
private Optional<Long> getLastModifiedInMilliseconds(Object object) {
|
||||
|
||||
return getAuditableBeanWrapper(object)//
|
||||
.flatMap(it -> it.getLastModifiedDate())//
|
||||
.map(it -> conversionService.convert(it, Date.class))//
|
||||
.map(it -> conversionService.convert(it, Instant.class))//
|
||||
.map(it -> it.toEpochMilli());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
|
||||
private Builder wrap(Object instance, Object source) {
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(source.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(source.getClass());
|
||||
|
||||
return PersistentEntityResource.build(instance, entity).//
|
||||
withEmbedded(getEmbeddedResources(source)).//
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -44,7 +45,6 @@ import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.ResourceType;
|
||||
import org.springframework.data.rest.core.mapping.SearchResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.SupportedHttpMethods;
|
||||
import org.springframework.data.rest.core.util.Supplier;
|
||||
import org.springframework.data.rest.webmvc.support.BackendId;
|
||||
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
|
||||
import org.springframework.data.rest.webmvc.support.ETag;
|
||||
@@ -305,18 +305,16 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
public ResponseEntity<?> headForItemResource(RootResourceInformation resourceInformation, @BackendId Serializable id,
|
||||
PersistentEntityResourceAssembler assembler) throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
Object domainObject = getItemResource(resourceInformation, id);
|
||||
return getItemResource(resourceInformation, id).map(it -> {
|
||||
|
||||
if (domainObject == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
Links links = new Links(assembler.toResource(it).getLinks());
|
||||
|
||||
Links links = new Links(assembler.toResource(domainObject).getLinks());
|
||||
HttpHeaders headers = headersPreparer.prepareHeaders(resourceInformation.getPersistentEntity(), it);
|
||||
headers.add(LINK_HEADER, links.toString());
|
||||
|
||||
HttpHeaders headers = headersPreparer.prepareHeaders(resourceInformation.getPersistentEntity(), domainObject);
|
||||
headers.add(LINK_HEADER, links.toString());
|
||||
return new ResponseEntity<Object>(headers, HttpStatus.NO_CONTENT);
|
||||
|
||||
return new ResponseEntity<Object>(headers, HttpStatus.NO_CONTENT);
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,21 +330,14 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
@BackendId Serializable id, final PersistentEntityResourceAssembler assembler, @RequestHeader HttpHeaders headers)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
final Object domainObj = getItemResource(resourceInformation, id);
|
||||
return getItemResource(resourceInformation, id).map(it -> {
|
||||
|
||||
if (domainObj == null) {
|
||||
return new ResponseEntity<Resource<?>>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
return resourceStatus.getStatusAndHeaders(headers, it, entity).toResponseEntity(//
|
||||
() -> assembler.toFullResource(it));
|
||||
|
||||
return resourceStatus.getStatusAndHeaders(headers, domainObj, entity).toResponseEntity(//
|
||||
new Supplier<PersistentEntityResource>() {
|
||||
@Override
|
||||
public PersistentEntityResource get() {
|
||||
return assembler.toFullResource(domainObj);
|
||||
}
|
||||
});
|
||||
}).orElseGet(() -> new ResponseEntity<Resource<?>>(HttpStatus.NOT_FOUND));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -425,21 +416,21 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
resourceInformation.verifySupportedMethod(HttpMethod.DELETE, ResourceType.ITEM);
|
||||
|
||||
RepositoryInvoker invoker = resourceInformation.getInvoker();
|
||||
Object domainObj = invoker.invokeFindOne(id);
|
||||
Optional<Object> domainObj = invoker.invokeFindOne(id);
|
||||
|
||||
if (domainObj == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
return domainObj.map(it -> {
|
||||
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
|
||||
eTag.verify(entity, domainObj);
|
||||
eTag.verify(entity, it);
|
||||
|
||||
publisher.publishEvent(new BeforeDeleteEvent(domainObj));
|
||||
invoker.invokeDelete((Serializable) entity.getIdentifierAccessor(domainObj).getIdentifier());
|
||||
publisher.publishEvent(new AfterDeleteEvent(domainObj));
|
||||
publisher.publishEvent(new BeforeDeleteEvent(it));
|
||||
invoker.invokeDelete((Serializable) entity.getIdentifierAccessor(it).getIdentifier().orElse(null));
|
||||
publisher.publishEvent(new AfterDeleteEvent(it));
|
||||
|
||||
return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);
|
||||
return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);
|
||||
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -458,7 +449,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
publisher.publishEvent(new AfterSaveEvent(obj));
|
||||
|
||||
PersistentEntityResource resource = assembler.toFullResource(obj);
|
||||
HttpHeaders headers = headersPreparer.prepareHeaders(resource);
|
||||
HttpHeaders headers = headersPreparer.prepareHeaders(Optional.of(resource));
|
||||
|
||||
if (PUT.equals(httpMethod)) {
|
||||
addLocationHeader(headers, assembler, obj);
|
||||
@@ -485,7 +476,8 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
Object savedObject = invoker.invokeSave(domainObject);
|
||||
publisher.publishEvent(new AfterCreateEvent(savedObject));
|
||||
|
||||
PersistentEntityResource resource = returnBody ? assembler.toFullResource(savedObject) : null;
|
||||
Optional<PersistentEntityResource> resource = Optional
|
||||
.ofNullable(returnBody ? assembler.toFullResource(savedObject) : null);
|
||||
|
||||
HttpHeaders headers = headersPreparer.prepareHeaders(resource);
|
||||
addLocationHeader(headers, assembler, savedObject);
|
||||
@@ -516,7 +508,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
* @throws {@link ResourceNotFoundException}
|
||||
*/
|
||||
private Object getItemResource(RootResourceInformation resourceInformation, Serializable id)
|
||||
private Optional<Object> getItemResource(RootResourceInformation resourceInformation, Serializable id)
|
||||
throws HttpRequestMethodNotSupportedException, ResourceNotFoundException {
|
||||
|
||||
resourceInformation.verifySupportedMethod(HttpMethod.GET, ResourceType.ITEM);
|
||||
|
||||
@@ -20,6 +20,9 @@ import static org.springframework.data.rest.webmvc.RestMediaTypes.*;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -30,6 +33,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -49,7 +54,6 @@ import org.springframework.data.rest.core.event.BeforeLinkSaveEvent;
|
||||
import org.springframework.data.rest.core.mapping.PropertyAwareResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.util.Function;
|
||||
import org.springframework.data.rest.webmvc.support.BackendId;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.Link;
|
||||
@@ -62,7 +66,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -111,72 +115,55 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
|
||||
Function<ReferencedProperty, ResourceSupport> handler = prop -> prop.propertyValue.map(it -> {
|
||||
|
||||
@Override
|
||||
public ResourceSupport apply(ReferencedProperty prop) {
|
||||
if (prop.property.isCollectionLike()) {
|
||||
|
||||
if (null == prop.propertyValue) {
|
||||
throw new ResourceNotFoundException();
|
||||
return toResources((Iterable<?>) it, assembler, prop.propertyType, null);
|
||||
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
Map<Object, Resource<?>> resources = new HashMap<Object, Resource<?>>();
|
||||
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) it).entrySet()) {
|
||||
resources.put(entry.getKey(), assembler.toResource(entry.getValue()));
|
||||
}
|
||||
|
||||
if (prop.property.isCollectionLike()) {
|
||||
return new Resource<Object>(resources);
|
||||
|
||||
return toResources((Iterable<?>) prop.propertyValue, assembler, prop.propertyType, null);
|
||||
} else {
|
||||
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
Map<Object, Resource<?>> resources = new HashMap<Object, Resource<?>>();
|
||||
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
|
||||
resources.put(entry.getKey(), assembler.toResource(entry.getValue()));
|
||||
}
|
||||
|
||||
return new Resource<Object>(resources);
|
||||
|
||||
} else {
|
||||
|
||||
PersistentEntityResource resource = assembler.toResource(prop.propertyValue);
|
||||
headers.set("Content-Location", resource.getId().getHref());
|
||||
return resource;
|
||||
}
|
||||
PersistentEntityResource resource = assembler.toResource(it);
|
||||
headers.set("Content-Location", resource.getId().getHref());
|
||||
return resource;
|
||||
}
|
||||
};
|
||||
|
||||
ResourceSupport responseResource = doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.GET);
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, responseResource);
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, //
|
||||
doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.GET));
|
||||
}
|
||||
|
||||
@RequestMapping(value = BASE_MAPPING, method = DELETE)
|
||||
public ResponseEntity<? extends ResourceSupport> deletePropertyReference(final RootResourceInformation repoRequest,
|
||||
@BackendId Serializable id, @PathVariable String property) throws Exception {
|
||||
|
||||
final RepositoryInvoker repoMethodInvoker = repoRequest.getInvoker();
|
||||
Function<ReferencedProperty, ResourceSupport> handler = prop -> prop.propertyValue.map(it -> {
|
||||
|
||||
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
|
||||
|
||||
@Override
|
||||
public Resource<?> apply(ReferencedProperty prop) throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
if (null == prop.propertyValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prop.property.isCollectionLike()) {
|
||||
throw new HttpRequestMethodNotSupportedException("DELETE");
|
||||
} else if (prop.property.isMap()) {
|
||||
throw new HttpRequestMethodNotSupportedException("DELETE");
|
||||
} else {
|
||||
prop.accessor.setProperty(prop.property, null);
|
||||
}
|
||||
|
||||
publisher.publishEvent(new BeforeLinkDeleteEvent(prop.accessor.getBean(), prop.propertyValue));
|
||||
Object result = repoMethodInvoker.invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkDeleteEvent(result, prop.propertyValue));
|
||||
|
||||
return null;
|
||||
if (prop.property.isCollectionLike() || prop.property.isMap()) {
|
||||
throw HttpRequestMethodNotSupportedException.forRejectedMethod(HttpMethod.DELETE)
|
||||
.withAllowedMethods(HttpMethod.GET, HttpMethod.HEAD);
|
||||
} else {
|
||||
prop.wipeValue();
|
||||
}
|
||||
};
|
||||
|
||||
publisher.publishEvent(new BeforeLinkDeleteEvent(prop.accessor.getBean(), prop.propertyValue));
|
||||
Object result = repoRequest.getInvoker().invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkDeleteEvent(result, prop.propertyValue));
|
||||
|
||||
return (ResourceSupport) null;
|
||||
|
||||
}).orElse(null);
|
||||
|
||||
doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.DELETE);
|
||||
|
||||
@@ -190,53 +177,51 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
|
||||
Function<ReferencedProperty, ResourceSupport> handler = prop -> prop.propertyValue.map(it -> {
|
||||
|
||||
@Override
|
||||
public ResourceSupport apply(ReferencedProperty prop) {
|
||||
if (prop.property.isCollectionLike()) {
|
||||
|
||||
if (null == prop.propertyValue) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
if (prop.property.isCollectionLike()) {
|
||||
for (Object obj : (Iterable<?>) prop.propertyValue) {
|
||||
for (Object obj : (Iterable<?>) it) {
|
||||
|
||||
IdentifierAccessor accessor = prop.entity.getIdentifierAccessor(obj);
|
||||
if (propertyId.equals(accessor.getIdentifier().toString())) {
|
||||
IdentifierAccessor accessor1 = prop.entity.getIdentifierAccessor(obj);
|
||||
if (propertyId.equals(accessor1.getIdentifier().toString())) {
|
||||
|
||||
PersistentEntityResource resource = assembler.toResource(obj);
|
||||
headers.set("Content-Location", resource.getId().getHref());
|
||||
return resource;
|
||||
}
|
||||
PersistentEntityResource resource1 = assembler.toResource(obj);
|
||||
headers.set("Content-Location", resource1.getId().getHref());
|
||||
return resource1;
|
||||
}
|
||||
} else if (prop.property.isMap()) {
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
|
||||
|
||||
IdentifierAccessor accessor = prop.entity.getIdentifierAccessor(entry.getValue());
|
||||
if (propertyId.equals(accessor.getIdentifier().toString())) {
|
||||
|
||||
PersistentEntityResource resource = assembler.toResource(entry.getValue());
|
||||
headers.set("Content-Location", resource.getId().getHref());
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return new Resource<Object>(prop.propertyValue);
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException();
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) it).entrySet()) {
|
||||
|
||||
IdentifierAccessor accessor2 = prop.entity.getIdentifierAccessor(entry.getValue());
|
||||
if (propertyId.equals(accessor2.getIdentifier().toString())) {
|
||||
|
||||
PersistentEntityResource resource2 = assembler.toResource(entry.getValue());
|
||||
headers.set("Content-Location", resource2.getId().getHref());
|
||||
return resource2;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return new Resource<Object>(prop.propertyValue);
|
||||
}
|
||||
};
|
||||
|
||||
ResourceSupport responseResource = doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.GET);
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, responseResource);
|
||||
throw new ResourceNotFoundException();
|
||||
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, //
|
||||
doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.GET));
|
||||
}
|
||||
|
||||
@RequestMapping(value = BASE_MAPPING, method = GET,
|
||||
produces = { SPRING_DATA_COMPACT_JSON_VALUE, TEXT_URI_LIST_VALUE })
|
||||
public ResponseEntity<ResourceSupport> followPropertyReferenceCompact(RootResourceInformation repoRequest,
|
||||
@BackendId Serializable id, @PathVariable String property, PersistentEntityResourceAssembler assembler)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
|
||||
ResponseEntity<ResourceSupport> response = followPropertyReference(repoRequest, id, property, assembler);
|
||||
|
||||
@@ -245,7 +230,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
}
|
||||
|
||||
ResourceMetadata repoMapping = repoRequest.getResourceMetadata();
|
||||
PersistentProperty<?> persistentProp = repoRequest.getPersistentEntity().getPersistentProperty(property);
|
||||
PersistentProperty<?> persistentProp = repoRequest.getPersistentEntity().getRequiredPersistentProperty(property);
|
||||
ResourceMapping propertyMapping = repoMapping.getMappingFor(persistentProp);
|
||||
|
||||
ResourceSupport resource = response.getBody();
|
||||
@@ -291,60 +276,59 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
final Resources<Object> source = incoming == null ? new Resources<Object>(Collections.emptyList()) : incoming;
|
||||
final RepositoryInvoker invoker = resourceInformation.getInvoker();
|
||||
|
||||
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
|
||||
Function<ReferencedProperty, ResourceSupport> handler = prop -> {
|
||||
|
||||
@Override
|
||||
public ResourceSupport apply(ReferencedProperty prop) throws HttpRequestMethodNotSupportedException {
|
||||
Class<?> propertyType = prop.property.getType();
|
||||
|
||||
Class<?> propertyType = prop.property.getType();
|
||||
if (prop.property.isCollectionLike()) {
|
||||
|
||||
if (prop.property.isCollectionLike()) {
|
||||
Collection<Object> collection = AUGMENTING_METHODS.contains(requestMethod)
|
||||
? (Collection<Object>) prop.propertyValue.orElse(null)
|
||||
: CollectionFactory.createCollection(propertyType, 0);
|
||||
|
||||
Collection<Object> collection = AUGMENTING_METHODS.contains(requestMethod)
|
||||
? (Collection<Object>) prop.propertyValue : CollectionFactory.createCollection(propertyType, 0);
|
||||
|
||||
// Add to the existing collection
|
||||
for (Link l : source.getLinks()) {
|
||||
collection.add(loadPropertyValue(prop.propertyType, l));
|
||||
}
|
||||
|
||||
prop.accessor.setProperty(prop.property, collection);
|
||||
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
Map<String, Object> map = AUGMENTING_METHODS.contains(requestMethod)
|
||||
? (Map<String, Object>) prop.propertyValue
|
||||
: CollectionFactory.<String, Object> createMap(propertyType, 0);
|
||||
|
||||
// Add to the existing collection
|
||||
for (Link l : source.getLinks()) {
|
||||
map.put(l.getRel(), loadPropertyValue(prop.propertyType, l));
|
||||
}
|
||||
|
||||
prop.accessor.setProperty(prop.property, map);
|
||||
|
||||
} else {
|
||||
|
||||
if (HttpMethod.PATCH.equals(requestMethod)) {
|
||||
throw new HttpRequestMethodNotSupportedException(HttpMethod.PATCH.name(), new String[] { "PATCH" },
|
||||
"Cannot PATCH a reference to this singular property since the property type is not a List or a Map.");
|
||||
}
|
||||
|
||||
if (source.getLinks().size() != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Must send only 1 link to update a property reference that isn't a List or a Map.");
|
||||
}
|
||||
|
||||
Object propVal = loadPropertyValue(prop.propertyType, source.getLinks().get(0));
|
||||
prop.accessor.setProperty(prop.property, propVal);
|
||||
// Add to the existing collection
|
||||
for (Link l1 : source.getLinks()) {
|
||||
collection.add(loadPropertyValue(prop.propertyType, l1).orElse(null));
|
||||
}
|
||||
|
||||
publisher.publishEvent(new BeforeLinkSaveEvent(prop.accessor.getBean(), prop.propertyValue));
|
||||
Object result = invoker.invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkSaveEvent(result, prop.propertyValue));
|
||||
prop.accessor.setProperty(prop.property, Optional.of(collection));
|
||||
|
||||
return null;
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
Map<String, Object> map = AUGMENTING_METHODS.contains(requestMethod)
|
||||
? (Map<String, Object>) prop.propertyValue.orElse(null)
|
||||
: CollectionFactory.<String, Object> createMap(propertyType, 0);
|
||||
|
||||
// Add to the existing collection
|
||||
for (Link l2 : source.getLinks()) {
|
||||
map.put(l2.getRel(), loadPropertyValue(prop.propertyType, l2).orElse(null));
|
||||
}
|
||||
|
||||
prop.accessor.setProperty(prop.property, Optional.of(map));
|
||||
|
||||
} else {
|
||||
|
||||
if (HttpMethod.PATCH.equals(requestMethod)) {
|
||||
throw HttpRequestMethodNotSupportedException.forRejectedMethod(HttpMethod.PATCH)//
|
||||
.withAllowedMethods(HttpMethod.PATCH)//
|
||||
.withMessage(
|
||||
"Cannot PATCH a reference to this singular property since the property type is not a List or a Map.");
|
||||
}
|
||||
|
||||
if (source.getLinks().size() != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Must send only 1 link to update a property reference that isn't a List or a Map.");
|
||||
}
|
||||
|
||||
Optional<Object> propVal = loadPropertyValue(prop.propertyType, source.getLinks().get(0));
|
||||
prop.accessor.setProperty(prop.property, propVal);
|
||||
}
|
||||
|
||||
publisher.publishEvent(new BeforeLinkSaveEvent(prop.accessor.getBean(), prop.propertyValue));
|
||||
Object result = invoker.invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkSaveEvent(result, prop.propertyValue));
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
doWithReferencedProperty(resourceInformation, id, property, handler, requestMethod);
|
||||
@@ -354,68 +338,59 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
@RequestMapping(value = BASE_MAPPING + "/{propertyId}", method = DELETE)
|
||||
public ResponseEntity<ResourceSupport> deletePropertyReferenceId(final RootResourceInformation repoRequest,
|
||||
@BackendId Serializable id, @PathVariable String property, final @PathVariable String propertyId)
|
||||
throws Exception {
|
||||
@BackendId Serializable backendId, @PathVariable String property, final @PathVariable String propertyId)
|
||||
throws Exception {
|
||||
|
||||
final RepositoryInvoker invoker = repoRequest.getInvoker();
|
||||
Function<ReferencedProperty, ResourceSupport> handler = prop -> prop.propertyValue.map(it -> {
|
||||
|
||||
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
|
||||
if (prop.property.isCollectionLike()) {
|
||||
|
||||
@Override
|
||||
public ResourceSupport apply(ReferencedProperty prop) {
|
||||
Collection<Object> coll = (Collection<Object>) it;
|
||||
Iterator<Object> iterator = coll.iterator();
|
||||
|
||||
if (null == prop.propertyValue) {
|
||||
return null;
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
Object obj = iterator.next();
|
||||
|
||||
prop.entity.getIdentifierAccessor(obj).getIdentifier()//
|
||||
.map(Object::toString)//
|
||||
.filter(id -> propertyId.equals(id))//
|
||||
.ifPresent(__ -> iterator.remove());
|
||||
}
|
||||
|
||||
if (prop.property.isCollectionLike()) {
|
||||
Collection<Object> coll = (Collection<Object>) prop.propertyValue;
|
||||
Iterator<Object> itr = coll.iterator();
|
||||
while (itr.hasNext()) {
|
||||
Object obj = itr.next();
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
IdentifierAccessor accessor = prop.entity.getIdentifierAccessor(obj);
|
||||
String s = accessor.getIdentifier().toString();
|
||||
Map<Object, Object> m = (Map<Object, Object>) it;
|
||||
Iterator<Entry<Object, Object>> iterator = m.entrySet().iterator();
|
||||
|
||||
if (propertyId.equals(s)) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
} else if (prop.property.isMap()) {
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
Map<Object, Object> m = (Map<Object, Object>) prop.propertyValue;
|
||||
Iterator<Entry<Object, Object>> itr = m.entrySet().iterator();
|
||||
Object key = iterator.next().getKey();
|
||||
|
||||
while (itr.hasNext()) {
|
||||
|
||||
Object key = itr.next().getKey();
|
||||
|
||||
IdentifierAccessor accessor = prop.entity.getIdentifierAccessor(m.get(key));
|
||||
String s = accessor.getIdentifier().toString();
|
||||
|
||||
if (propertyId.equals(s)) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
prop.accessor.setProperty(prop.property, null);
|
||||
prop.entity.getIdentifierAccessor(m.get(key)).getIdentifier()//
|
||||
.map(Object::toString)//
|
||||
.filter(id -> propertyId.equals(id))//
|
||||
.ifPresent(__ -> iterator.remove());
|
||||
}
|
||||
|
||||
publisher.publishEvent(new BeforeLinkDeleteEvent(prop.accessor.getBean(), prop.propertyValue));
|
||||
Object result = invoker.invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkDeleteEvent(result, prop.propertyValue));
|
||||
|
||||
return null;
|
||||
} else {
|
||||
prop.wipeValue();
|
||||
}
|
||||
};
|
||||
|
||||
doWithReferencedProperty(repoRequest, id, property, handler, HttpMethod.DELETE);
|
||||
publisher.publishEvent(new BeforeLinkDeleteEvent(prop.accessor.getBean(), it));
|
||||
Object result = repoRequest.getInvoker().invokeSave(prop.accessor.getBean());
|
||||
publisher.publishEvent(new AfterLinkDeleteEvent(result, it));
|
||||
|
||||
return (ResourceSupport) null;
|
||||
|
||||
}).orElse(null);
|
||||
|
||||
doWithReferencedProperty(repoRequest, backendId, property, handler, HttpMethod.DELETE);
|
||||
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
private Object loadPropertyValue(Class<?> type, Link link) {
|
||||
private Optional<Object> loadPropertyValue(Class<?> type, Link link) {
|
||||
|
||||
String href = link.expand().getHref();
|
||||
String id = href.substring(href.lastIndexOf('/') + 1);
|
||||
@@ -425,8 +400,9 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
return invoker.invokeFindOne(id);
|
||||
}
|
||||
|
||||
private ResourceSupport doWithReferencedProperty(RootResourceInformation resourceInformation, Serializable id,
|
||||
String propertyPath, Function<ReferencedProperty, ResourceSupport> handler, HttpMethod method) throws Exception {
|
||||
private Optional<ResourceSupport> doWithReferencedProperty(RootResourceInformation resourceInformation,
|
||||
Serializable id, String propertyPath, Function<ReferencedProperty, ResourceSupport> handler, HttpMethod method)
|
||||
throws Exception {
|
||||
|
||||
ResourceMetadata metadata = resourceInformation.getResourceMetadata();
|
||||
PropertyAwareResourceMapping mapping = metadata.getProperty(propertyPath);
|
||||
@@ -439,14 +415,15 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
resourceInformation.verifySupportedMethod(method, property);
|
||||
|
||||
RepositoryInvoker invoker = resourceInformation.getInvoker();
|
||||
Object domainObj = invoker.invokeFindOne(id);
|
||||
Optional<Object> domainObj = invoker.invokeFindOne(id);
|
||||
|
||||
if (null == domainObj) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
domainObj.orElseThrow(() -> new ResourceNotFoundException());
|
||||
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(domainObj);
|
||||
return handler.apply(new ReferencedProperty(property, accessor.getProperty(property), accessor));
|
||||
return domainObj.map(it -> {
|
||||
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(it);
|
||||
return handler.apply(new ReferencedProperty(property, accessor.getProperty(property), accessor));
|
||||
});
|
||||
}
|
||||
|
||||
private class ReferencedProperty {
|
||||
@@ -454,10 +431,10 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
final PersistentEntity<?, ?> entity;
|
||||
final PersistentProperty<?> property;
|
||||
final Class<?> propertyType;
|
||||
final Object propertyValue;
|
||||
final Optional<Object> propertyValue;
|
||||
final PersistentPropertyAccessor accessor;
|
||||
|
||||
private ReferencedProperty(PersistentProperty<?> property, Object propertyValue,
|
||||
private ReferencedProperty(PersistentProperty<?> property, Optional<Object> propertyValue,
|
||||
PersistentPropertyAccessor wrapper) {
|
||||
|
||||
this.property = property;
|
||||
@@ -466,5 +443,54 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
this.propertyType = property.getActualType();
|
||||
this.entity = repositories.getPersistentEntity(propertyType);
|
||||
}
|
||||
|
||||
public void writeValue() {
|
||||
accessor.setProperty(property, propertyValue);
|
||||
}
|
||||
|
||||
public void wipeValue() {
|
||||
accessor.setProperty(property, Optional.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
public ResponseEntity<Void> handle(HttpRequestMethodNotSupportedException exception) {
|
||||
return exception.toResponse();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
static class HttpRequestMethodNotSupportedException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3704212056962845475L;
|
||||
|
||||
private final HttpMethod rejectedMethod;
|
||||
private final HttpMethod[] allowedMethods;
|
||||
private final String message;
|
||||
|
||||
public static HttpRequestMethodNotSupportedException forRejectedMethod(HttpMethod method) {
|
||||
return new HttpRequestMethodNotSupportedException(method, new HttpMethod[0], null);
|
||||
}
|
||||
|
||||
public HttpRequestMethodNotSupportedException withAllowedMethods(HttpMethod... methods) {
|
||||
return new HttpRequestMethodNotSupportedException(this.rejectedMethod, methods.clone(), null);
|
||||
}
|
||||
|
||||
public HttpRequestMethodNotSupportedException withMessage(String message, Object... parameters) {
|
||||
return new HttpRequestMethodNotSupportedException(this.rejectedMethod, this.allowedMethods,
|
||||
String.format(message, parameters));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Throwable#getMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public ResponseEntity<Void> toResponse() {
|
||||
return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).allow(allowedMethods).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
@@ -63,7 +64,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
|
||||
|
||||
private final ResourceMappings mappings;
|
||||
private final RepositoryRestConfiguration configuration;
|
||||
private final Repositories repositories;
|
||||
private final Optional<Repositories> repositories;
|
||||
|
||||
private RepositoryCorsConfigurationAccessor corsConfigurationAccessor;
|
||||
private JpaHelper jpaHelper;
|
||||
@@ -76,7 +77,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
|
||||
* @param config must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryRestHandlerMapping(ResourceMappings mappings, RepositoryRestConfiguration config) {
|
||||
this(mappings, config, null);
|
||||
this(mappings, config, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,15 +86,22 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
|
||||
*
|
||||
* @param mappings must not be {@literal null}.
|
||||
* @param config must not be {@literal null}.
|
||||
* @param repositories can be {@literal null} if {@link CrossOrigin} resolution is not required.
|
||||
* @param repositories must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryRestHandlerMapping(ResourceMappings mappings, RepositoryRestConfiguration config,
|
||||
Repositories repositories) {
|
||||
|
||||
this(mappings, config, Optional.of(repositories));
|
||||
}
|
||||
|
||||
private RepositoryRestHandlerMapping(ResourceMappings mappings, RepositoryRestConfiguration config,
|
||||
Optional<Repositories> repositories) {
|
||||
|
||||
super(config);
|
||||
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
Assert.notNull(config, "RepositoryRestConfiguration must not be null!");
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
|
||||
this.mappings = mappings;
|
||||
this.configuration = config;
|
||||
@@ -201,19 +209,14 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
|
||||
@Override
|
||||
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
|
||||
|
||||
CorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, request);
|
||||
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
String repositoryLookupPath = new BaseUri(configuration.getBaseUri()).getRepositoryLookupPath(lookupPath);
|
||||
CorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, request);
|
||||
|
||||
if (!StringUtils.hasText(repositoryLookupPath) || repositories == null) {
|
||||
return corsConfiguration;
|
||||
}
|
||||
|
||||
CorsConfiguration repositoryCorsConfiguration = corsConfigurationAccessor.findCorsConfiguration(lookupPath);
|
||||
|
||||
return corsConfiguration == null ? repositoryCorsConfiguration
|
||||
: corsConfiguration.combine(repositoryCorsConfiguration);
|
||||
return repositories.filter(it -> StringUtils.hasText(repositoryLookupPath))//
|
||||
.flatMap(it -> corsConfigurationAccessor.findCorsConfiguration(lookupPath))
|
||||
.map(it -> it.combine(corsConfiguration))//
|
||||
.orElse(corsConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,28 +265,25 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
|
||||
|
||||
private final @NonNull ResourceMappings mappings;
|
||||
private final @NonNull StringValueResolver embeddedValueResolver;
|
||||
private final Repositories repositories;
|
||||
private final @NonNull Optional<Repositories> repositories;
|
||||
|
||||
CorsConfiguration findCorsConfiguration(String lookupPath) {
|
||||
Optional<CorsConfiguration> findCorsConfiguration(String lookupPath) {
|
||||
|
||||
ResourceMetadata resource = getResourceMetadata(getRepositoryBasePath(lookupPath));
|
||||
|
||||
return resource != null && repositories != null ? createConfiguration(
|
||||
repositories.getRepositoryInformationFor(resource.getDomainType()).getRepositoryInterface()) : null;
|
||||
return getResourceMetadata(getRepositoryBasePath(lookupPath))//
|
||||
.flatMap(it -> repositories.flatMap(foo -> foo.getRepositoryInformationFor(it.getDomainType())))//
|
||||
.map(it -> it.getRepositoryInterface())//
|
||||
.map(it -> createConfiguration(it));
|
||||
}
|
||||
|
||||
private ResourceMetadata getResourceMetadata(String basePath) {
|
||||
private Optional<ResourceMetadata> getResourceMetadata(String basePath) {
|
||||
|
||||
if (mappings.exportsTopLevelResourceFor(basePath)) {
|
||||
|
||||
for (ResourceMetadata metadata : mappings) {
|
||||
if (metadata.getPath().matches(basePath) && metadata.isExported()) {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
if (!mappings.exportsTopLevelResourceFor(basePath)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return null;
|
||||
return mappings.stream()//
|
||||
.filter(it -> it.getPath().matches(basePath) && it.isExported())//
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -35,7 +36,6 @@ import org.springframework.data.rest.core.mapping.MethodResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.SearchResourceMappings;
|
||||
import org.springframework.data.rest.core.util.Supplier;
|
||||
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
@@ -180,7 +180,8 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
Sort sort, PersistentEntityResourceAssembler assembler, @RequestHeader HttpHeaders headers) {
|
||||
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort, assembler);
|
||||
Optional<Object> result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort,
|
||||
assembler);
|
||||
|
||||
SearchResourceMappings searchMappings = resourceInformation.getSearchMappings();
|
||||
MethodResourceMapping methodMapping = searchMappings.getExportedMethodMappingForPath(search);
|
||||
@@ -199,27 +200,23 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
* @param baseLink can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected ResponseEntity<?> toResource(final Object source, final PersistentEntityResourceAssembler assembler,
|
||||
protected ResponseEntity<?> toResource(Optional<Object> source, final PersistentEntityResourceAssembler assembler,
|
||||
Class<?> domainType, Link baseLink, HttpHeaders headers, RootResourceInformation information) {
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
return ResponseEntity.ok(toResources((Iterable<?>) source, assembler, domainType, baseLink));
|
||||
} else if (source == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
} else if (ClassUtils.isPrimitiveOrWrapper(source.getClass())) {
|
||||
return ResponseEntity.ok(source);
|
||||
}
|
||||
return source.map(it -> {
|
||||
|
||||
PersistentEntity<?, ?> entity = information.getPersistentEntity();
|
||||
if (it instanceof Iterable) {
|
||||
return ResponseEntity.ok(toResources((Iterable<?>) it, assembler, domainType, baseLink));
|
||||
} else if (ClassUtils.isPrimitiveOrWrapper(it.getClass())) {
|
||||
return ResponseEntity.ok(it);
|
||||
}
|
||||
|
||||
return resourceStatus.getStatusAndHeaders(headers, source, entity).toResponseEntity(//
|
||||
new Supplier<PersistentEntityResource>() {
|
||||
PersistentEntity<?, ?> entity = information.getPersistentEntity();
|
||||
|
||||
@Override
|
||||
public PersistentEntityResource get() {
|
||||
return assembler.toFullResource(source);
|
||||
}
|
||||
});
|
||||
return resourceStatus.getStatusAndHeaders(headers, it, entity).toResponseEntity(//
|
||||
() -> assembler.toFullResource(it));
|
||||
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +240,8 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
PersistentEntityResourceAssembler assembler) {
|
||||
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort, assembler);
|
||||
Optional<Object> result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort,
|
||||
assembler);
|
||||
ResourceMetadata metadata = resourceInformation.getResourceMetadata();
|
||||
ResponseEntity<?> entity = toResource(result, assembler, metadata.getDomainType(), null, headers,
|
||||
resourceInformation);
|
||||
@@ -331,7 +329,7 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
* @param pageable
|
||||
* @return
|
||||
*/
|
||||
private Object executeQueryMethod(final RepositoryInvoker invoker,
|
||||
private Optional<Object> executeQueryMethod(final RepositoryInvoker invoker,
|
||||
@RequestParam MultiValueMap<String, Object> parameters, Method method, DefaultedPageable pageable, Sort sort,
|
||||
PersistentEntityResourceAssembler assembler) {
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.rest.core.util.Supplier;
|
||||
import org.springframework.data.rest.webmvc.support.ETag;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
@@ -256,7 +256,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
*/
|
||||
private List<Descriptor> getPaginationDescriptors(Class<?> type, HttpMethod method) {
|
||||
|
||||
RepositoryInformation information = repositories.getRepositoryInformationFor(type);
|
||||
RepositoryInformation information = repositories.getRequiredRepositoryInformation(type);
|
||||
|
||||
if (!information.isPagingRepository() || !getType(method).equals(Type.SAFE)) {
|
||||
return Collections.emptyList();
|
||||
@@ -290,7 +290,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
|
||||
private List<Descriptor> buildPropertyDescriptors(final Class<?> type, String baseRel) {
|
||||
|
||||
final PersistentEntity<?, ?> entity = persistentEntities.getPersistentEntity(type);
|
||||
final PersistentEntity<?, ?> entity = persistentEntities.getRequiredPersistentEntity(type);
|
||||
final List<Descriptor> propertyDescriptors = new ArrayList<Descriptor>();
|
||||
final JacksonMetadata jackson = new JacksonMetadata(mapper, type);
|
||||
final ResourceMetadata metadata = associations.getMetadataFor(entity.getType());
|
||||
@@ -311,10 +311,10 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
|
||||
propertyDescriptors.add(//
|
||||
descriptor(). //
|
||||
type(Type.SEMANTIC).//
|
||||
name(propertyDefinition.getName()).//
|
||||
doc(getDocFor(propertyMapping.getDescription(), property)).//
|
||||
build());
|
||||
type(Type.SEMANTIC).//
|
||||
name(propertyDefinition.getName()).//
|
||||
doc(getDocFor(propertyMapping.getDescription(), property)).//
|
||||
build());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -333,7 +333,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
ResourceMapping mapping = metadata.getMappingFor(property);
|
||||
|
||||
DescriptorBuilder builder = descriptor().//
|
||||
name(mapping.getRel()).doc(getDocFor(mapping.getDescription()));
|
||||
name(mapping.getRel()).doc(getDocFor(mapping.getDescription()));
|
||||
|
||||
ResourceMetadata targetTypeMetadata = associations.getMetadataFor(property.getActualType());
|
||||
|
||||
@@ -343,8 +343,8 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
Link link = new Link(href).withSelfRel();
|
||||
|
||||
builder.//
|
||||
type(Type.SAFE).//
|
||||
rt(link.getHref());
|
||||
type(Type.SAFE).//
|
||||
rt(link.getHref());
|
||||
|
||||
propertyDescriptors.add(builder.build());
|
||||
}
|
||||
@@ -386,6 +386,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
return getDocFor(description, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Doc getDocFor(ResourceDescription description, PersistentProperty<?> property) {
|
||||
|
||||
if (description == null) {
|
||||
|
||||
@@ -18,12 +18,12 @@ package org.springframework.data.rest.webmvc.config;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.rest.webmvc.IncomingRequest;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource.Builder;
|
||||
@@ -124,16 +124,7 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha
|
||||
}
|
||||
|
||||
Serializable id = idResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
|
||||
Object objectToUpdate = getObjectToUpdate(id, resourceInformation);
|
||||
|
||||
boolean forUpdate = false;
|
||||
Object entityIdentifier = null;
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
|
||||
if (objectToUpdate != null) {
|
||||
forUpdate = true;
|
||||
entityIdentifier = entity.getIdentifierAccessor(objectToUpdate).getIdentifier();
|
||||
}
|
||||
Optional<Object> objectToUpdate = getObjectToUpdate(id, resourceInformation);
|
||||
|
||||
Object obj = read(resourceInformation, incoming, converter, objectToUpdate);
|
||||
|
||||
@@ -141,8 +132,13 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha
|
||||
throw new HttpMessageNotReadableException(String.format(ERROR_MESSAGE, domainType));
|
||||
}
|
||||
|
||||
if (entityIdentifier != null) {
|
||||
entity.getPropertyAccessor(obj).setProperty(entity.getIdProperty(), entityIdentifier);
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
boolean forUpdate = objectToUpdate.isPresent();
|
||||
Optional<Object> entityIdentifier = objectToUpdate
|
||||
.flatMap(it -> entity.getIdentifierAccessor(it).getIdentifier());
|
||||
|
||||
if (entityIdentifier.isPresent()) {
|
||||
entity.getPropertyAccessor(obj).setProperty(entity.getRequiredIdProperty(), entityIdentifier);
|
||||
}
|
||||
|
||||
Builder build = PersistentEntityResource.build(obj, entity);
|
||||
@@ -163,27 +159,25 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha
|
||||
* @return
|
||||
*/
|
||||
private Object read(RootResourceInformation information, IncomingRequest request,
|
||||
HttpMessageConverter<Object> converter, Object objectToUpdate) {
|
||||
HttpMessageConverter<Object> converter, Optional<Object> objectToUpdate) {
|
||||
|
||||
// JSON + PATCH request
|
||||
if (request.isPatchRequest() && converter instanceof MappingJackson2HttpMessageConverter) {
|
||||
|
||||
if (objectToUpdate == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
return objectToUpdate.map(it -> {
|
||||
|
||||
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
|
||||
Object result = readPatch(request, mapper, objectToUpdate);
|
||||
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
|
||||
return readPatch(request, mapper, it);
|
||||
|
||||
return result;
|
||||
}).orElseThrow(() -> new ResourceNotFoundException());
|
||||
|
||||
// JSON + PUT request
|
||||
} else if (converter instanceof MappingJackson2HttpMessageConverter) {
|
||||
|
||||
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
|
||||
|
||||
return objectToUpdate == null ? read(request, converter, information)
|
||||
: readPutForUpdate(request, mapper, objectToUpdate);
|
||||
return objectToUpdate.map(it -> readPutForUpdate(request, mapper, it))//
|
||||
.orElseGet(() -> read(request, converter, information));
|
||||
}
|
||||
|
||||
// Catch all
|
||||
@@ -238,13 +232,12 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha
|
||||
* @param information must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Object getObjectToUpdate(Serializable id, RootResourceInformation information) {
|
||||
private static Optional<Object> getObjectToUpdate(Serializable id, RootResourceInformation information) {
|
||||
|
||||
if (id == null) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
RepositoryInvoker invoker = information.getInvoker();
|
||||
return invoker.invokeFindOne(id);
|
||||
return information.getInvoker().invokeFindOne(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -20,7 +20,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.QuerydslRepositoryInvokerAdapter;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
@@ -76,22 +76,26 @@ class QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected RepositoryInvoker postProcess(MethodParameter parameter, RepositoryInvoker invoker,
|
||||
Class<?> domainType, Map<String, String[]> parameters) {
|
||||
protected RepositoryInvoker postProcess(MethodParameter parameter, RepositoryInvoker invoker, Class<?> domainType,
|
||||
Map<String, String[]> parameters) {
|
||||
|
||||
Object repository = repositories.getRepositoryFor(domainType);
|
||||
|
||||
if (!QueryDslPredicateExecutor.class.isInstance(repository)
|
||||
|| !parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
|
||||
if (!parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
|
||||
return invoker;
|
||||
}
|
||||
|
||||
ClassTypeInformation<?> type = ClassTypeInformation.from(domainType);
|
||||
return repositories.getRepositoryFor(domainType)//
|
||||
.filter(it -> QuerydslPredicateExecutor.class.isInstance(it))//
|
||||
.map(it -> {
|
||||
|
||||
QuerydslBindings bindings = factory.createBindingsFor(null, type);
|
||||
Predicate predicate = predicateBuilder.getPredicate(type, toMultiValueMap(parameters), bindings);
|
||||
ClassTypeInformation<?> type = ClassTypeInformation.from(domainType);
|
||||
|
||||
return new QuerydslRepositoryInvokerAdapter(invoker, (QueryDslPredicateExecutor<Object>) repository, predicate);
|
||||
QuerydslBindings bindings = factory.createBindingsFor(type);
|
||||
Predicate predicate = predicateBuilder.getPredicate(type, toMultiValueMap(parameters), bindings);
|
||||
|
||||
return (RepositoryInvoker) new QuerydslRepositoryInvokerAdapter(invoker,
|
||||
(QuerydslPredicateExecutor<Object>) it, predicate);
|
||||
|
||||
}).orElse(invoker);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.data.geo.GeoModule;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.querydsl.QueryDslUtils;
|
||||
import org.springframework.data.querydsl.QuerydslUtils;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
|
||||
import org.springframework.data.repository.support.DefaultRepositoryInvokerFactory;
|
||||
@@ -72,6 +72,7 @@ import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.RepositoryRelProvider;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.core.support.UnwrappingRepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.util.Java8PluginRegistry;
|
||||
import org.springframework.data.rest.webmvc.BasePathAwareController;
|
||||
import org.springframework.data.rest.webmvc.BasePathAwareHandlerMapping;
|
||||
import org.springframework.data.rest.webmvc.BaseUri;
|
||||
@@ -154,6 +155,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||
|
||||
/**
|
||||
* Main application configuration for Spring Data REST. To customize how the exporter works, subclass this and override
|
||||
@@ -189,6 +191,11 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
private RepositoryRestConfigurerDelegate configurerDelegate;
|
||||
|
||||
public RepositoryRestMvcConfiguration(ApplicationContext context,
|
||||
@Qualifier("mvcConversionService") ObjectFactory<ConversionService> conversionService) {
|
||||
super(context, conversionService);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
@@ -335,7 +342,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
@Bean
|
||||
public RootResourceInformationHandlerMethodArgumentResolver repoRequestArgumentResolver() {
|
||||
|
||||
if (QueryDslUtils.QUERY_DSL_PRESENT) {
|
||||
if (QuerydslUtils.QUERY_DSL_PRESENT) {
|
||||
|
||||
QuerydslBindingsFactory factory = applicationContext.getBean(QuerydslBindingsFactory.class);
|
||||
QuerydslPredicateBuilder predicateBuilder = new QuerydslPredicateBuilder(defaultConversionService(),
|
||||
@@ -357,7 +364,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
@Bean
|
||||
public BackendIdHandlerMethodArgumentResolver backendIdHandlerMethodArgumentResolver() {
|
||||
return new BackendIdHandlerMethodArgumentResolver(backendIdConverterRegistry(),
|
||||
return new BackendIdHandlerMethodArgumentResolver(Java8PluginRegistry.of(backendIdConverterRegistry()),
|
||||
resourceMetadataHandlerMethodArgumentResolver(), baseUri());
|
||||
}
|
||||
|
||||
@@ -380,7 +387,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
pageableResolver(), sortResolver());
|
||||
|
||||
return new RepositoryEntityLinks(repositories(), resourceMappings(), config(), templateVariables,
|
||||
backendIdConverterRegistry());
|
||||
Java8PluginRegistry.of(backendIdConverterRegistry()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,8 +450,12 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
|
||||
Jdk8Module jdk8Module = new Jdk8Module();
|
||||
jdk8Module.configureAbsentsAsNulls(true);
|
||||
|
||||
ObjectMapper mapper = basicObjectMapper();
|
||||
mapper.registerModule(persistentEntityJackson2Module());
|
||||
mapper.registerModule(jdk8Module);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
@@ -635,7 +646,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
EmbeddedResourcesAssembler assembler = new EmbeddedResourcesAssembler(entities, associationLinks(),
|
||||
excerptProjector());
|
||||
LookupObjectSerializer lookupObjectSerializer = new LookupObjectSerializer(
|
||||
OrderAwarePluginRegistry.create(getEntityLookups()));
|
||||
Java8PluginRegistry.of(getEntityLookups()));
|
||||
|
||||
return new PersistentEntityJackson2Module(associationLinks(), entities, uriToEntityConverter, linkCollector(),
|
||||
repositoryInvokerFactory, lookupObjectSerializer, resourceProcessorInvoker(), assembler);
|
||||
@@ -655,7 +666,6 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
projectionFactory.setBeanFactory(applicationContext);
|
||||
projectionFactory.setResourceLoader(applicationContext);
|
||||
|
||||
return new DefaultExcerptProjector(projectionFactory, resourceMappings());
|
||||
}
|
||||
@@ -732,7 +742,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
HateoasPageableHandlerMethodArgumentResolver resolver = super.pageableResolver();
|
||||
resolver.setPageParameterName(config().getPageParamName());
|
||||
resolver.setSizeParameterName(config().getLimitParamName());
|
||||
resolver.setFallbackPageable(new PageRequest(0, config().getDefaultPageSize()));
|
||||
resolver.setFallbackPageable(PageRequest.of(0, config().getDefaultPageSize()));
|
||||
resolver.setMaxPageSize(config().getMaxPageSize());
|
||||
|
||||
return resolver;
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.PropertyAccessor;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
@@ -107,9 +108,7 @@ public class DomainObjectReader {
|
||||
|
||||
Class<? extends Object> type = target.getClass();
|
||||
|
||||
final PersistentEntity<?, ?> entity = entities.getPersistentEntity(type);
|
||||
|
||||
Assert.notNull(entity, "No PersistentEntity found for ".concat(type.getName()).concat("!"));
|
||||
entities.getRequiredPersistentEntity(type);
|
||||
|
||||
try {
|
||||
|
||||
@@ -139,24 +138,20 @@ public class DomainObjectReader {
|
||||
|
||||
Class<? extends Object> type = target.getClass();
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(type);
|
||||
return entities.getPersistentEntity(type).map(it -> {
|
||||
|
||||
if (entity == null) {
|
||||
return source;
|
||||
}
|
||||
MergingPropertyHandler propertyHandler = new MergingPropertyHandler(source, target, it, mapper);
|
||||
|
||||
Assert.notNull(entity, "No PersistentEntity found for ".concat(type.getName()).concat("!"));
|
||||
it.doWithProperties(propertyHandler);
|
||||
it.doWithAssociations(new LinkedAssociationSkippingAssociationHandler(associationLinks, propertyHandler));
|
||||
|
||||
MergingPropertyHandler propertyHandler = new MergingPropertyHandler(source, target, entity, mapper);
|
||||
// Need to copy unmapped properties as the PersistentProperty model currently does not contain any transient
|
||||
// properties
|
||||
copyRemainingProperties(propertyHandler.getProperties(), source, target);
|
||||
|
||||
entity.doWithProperties(propertyHandler);
|
||||
entity.doWithAssociations(new LinkedAssociationSkippingAssociationHandler(associationLinks, propertyHandler));
|
||||
return target;
|
||||
|
||||
// Need to copy unmapped properties as the PersistentProperty model currently does not contain any transient
|
||||
// properties
|
||||
copyRemainingProperties(propertyHandler.getProperties(), source, target);
|
||||
|
||||
return target;
|
||||
}).orElse(source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,12 +208,14 @@ public class DomainObjectReader {
|
||||
Assert.notNull(target, "Target object instance must not be null!");
|
||||
Assert.notNull(mapper, "ObjectMapper must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(target.getClass());
|
||||
Optional<PersistentEntity<?, ? extends PersistentProperty<?>>> candidate = entities
|
||||
.getPersistentEntity(target.getClass());
|
||||
|
||||
if (entity == null) {
|
||||
if (!candidate.isPresent()) {
|
||||
return mapper.readerForUpdating(target).readValue(root);
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = candidate.get();
|
||||
MappedProperties mappedProperties = MappedProperties.fromJacksonProperties(entity, mapper);
|
||||
|
||||
for (Iterator<Entry<String, JsonNode>> i = root.fields(); i.hasNext();) {
|
||||
@@ -233,51 +230,57 @@ public class DomainObjectReader {
|
||||
|
||||
PersistentProperty<?> property = mappedProperties.getPersistentProperty(fieldName);
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(target);
|
||||
Object rawValue = accessor.getProperty(property);
|
||||
Optional<Object> rawValue = accessor.getProperty(property);
|
||||
|
||||
if (rawValue == null) {
|
||||
if (!rawValue.isPresent()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child.isArray()) {
|
||||
rawValue.ifPresent(it -> {
|
||||
|
||||
if (handleArray(child, rawValue, mapper, property.getTypeInformation())) {
|
||||
i.remove();
|
||||
}
|
||||
if (child.isArray()) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child.isObject()) {
|
||||
|
||||
if (associationLinks.isLinkableAssociation(property)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectNode objectNode = (ObjectNode) child;
|
||||
|
||||
if (property.isMap()) {
|
||||
|
||||
// Keep empty Map to wipe it as expected
|
||||
if (!objectNode.fieldNames().hasNext()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
doMergeNestedMap((Map<Object, Object>) rawValue, objectNode, mapper, property.getTypeInformation());
|
||||
|
||||
// Remove potentially emptied Map as values have been handled recursively
|
||||
if (!objectNode.fieldNames().hasNext()) {
|
||||
if (handleArray(child, it, mapper, property.getTypeInformation())) {
|
||||
i.remove();
|
||||
}
|
||||
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.isEntity()) {
|
||||
i.remove();
|
||||
doMerge(objectNode, rawValue, mapper);
|
||||
if (child.isObject()) {
|
||||
|
||||
if (associationLinks.isLinkableAssociation(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectNode objectNode = (ObjectNode) child;
|
||||
|
||||
if (property.isMap()) {
|
||||
|
||||
// Keep empty Map to wipe it as expected
|
||||
if (!objectNode.fieldNames().hasNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
execute(
|
||||
() -> doMergeNestedMap((Map<Object, Object>) it, objectNode, mapper, property.getTypeInformation()));
|
||||
|
||||
// Remove potentially emptied Map as values have been handled recursively
|
||||
if (!objectNode.fieldNames().hasNext()) {
|
||||
i.remove();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.isEntity()) {
|
||||
i.remove();
|
||||
execute(() -> doMerge(objectNode, it, mapper));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return mapper.readerForUpdating(target).readValue(root);
|
||||
@@ -295,8 +298,7 @@ public class DomainObjectReader {
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private boolean handleArray(JsonNode node, Object source, ObjectMapper mapper, TypeInformation<?> collectionType)
|
||||
throws Exception {
|
||||
private boolean handleArray(JsonNode node, Object source, ObjectMapper mapper, TypeInformation<?> collectionType) {
|
||||
|
||||
Collection<Object> collection = ifCollection(source);
|
||||
|
||||
@@ -304,7 +306,7 @@ public class DomainObjectReader {
|
||||
return false;
|
||||
}
|
||||
|
||||
return handleArrayNode((ArrayNode) node, collection, mapper, collectionType.getComponentType());
|
||||
return execute(() -> handleArrayNode((ArrayNode) node, collection, mapper, collectionType.getComponentType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +319,7 @@ public class DomainObjectReader {
|
||||
* @return whether an object merge has been applied to the {@link ArrayNode}.
|
||||
*/
|
||||
private boolean handleArrayNode(ArrayNode array, Collection<Object> collection, ObjectMapper mapper,
|
||||
TypeInformation<?> componentType) throws Exception {
|
||||
Optional<TypeInformation<?>> componentType) throws Exception {
|
||||
|
||||
Assert.notNull(array, "ArrayNode must not be null!");
|
||||
Assert.notNull(collection, "Source collection must not be null!");
|
||||
@@ -375,7 +377,7 @@ public class DomainObjectReader {
|
||||
|
||||
Iterator<Entry<String, JsonNode>> fields = node.fields();
|
||||
Class<?> keyType = typeOrObject(type.getComponentType());
|
||||
TypeInformation<?> valueType = type.getMapValueType();
|
||||
Optional<TypeInformation<?>> valueType = type.getMapValueType();
|
||||
|
||||
while (fields.hasNext()) {
|
||||
|
||||
@@ -393,7 +395,7 @@ public class DomainObjectReader {
|
||||
|
||||
} else if (value instanceof ArrayNode && sourceValue != null) {
|
||||
|
||||
handleArray(value, sourceValue, mapper, getTypeToMap(sourceValue, typeToMap));
|
||||
handleArray(value, sourceValue, mapper, getTypeToMap(sourceValue, Optional.of(typeToMap)));
|
||||
|
||||
} else {
|
||||
|
||||
@@ -405,89 +407,84 @@ public class DomainObjectReader {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Object, Object> mergeMaps(PersistentProperty<?> property, Object source, Object target,
|
||||
ObjectMapper mapper) {
|
||||
private Optional<Map<Object, Object>> mergeMaps(PersistentProperty<?> property, Optional<Object> source,
|
||||
Optional<Object> target, ObjectMapper mapper) {
|
||||
|
||||
Map<Object, Object> sourceMap = (Map<Object, Object>) source;
|
||||
return source.map(it -> {
|
||||
|
||||
if (sourceMap == null) {
|
||||
return null;
|
||||
}
|
||||
Map<Object, Object> sourceMap = (Map<Object, Object>) it;
|
||||
Map<Object, Object> targetMap = (Map<Object, Object>) target.orElse(null);
|
||||
|
||||
Map<Object, Object> targetMap = (Map<Object, Object>) target;
|
||||
Map<Object, Object> result = targetMap == null ? CollectionFactory.createMap(Map.class, sourceMap.size())
|
||||
: CollectionFactory.createApproximateMap(targetMap, sourceMap.size());
|
||||
Map<Object, Object> result = targetMap == null ? CollectionFactory.createMap(Map.class, sourceMap.size())
|
||||
: CollectionFactory.createApproximateMap(targetMap, sourceMap.size());
|
||||
|
||||
for (Entry<Object, Object> entry : sourceMap.entrySet()) {
|
||||
for (Entry<Object, Object> entry : sourceMap.entrySet()) {
|
||||
|
||||
Object targetValue = targetMap == null ? null : targetMap.get(entry.getKey());
|
||||
result.put(entry.getKey(), mergeForPut(entry.getValue(), targetValue, mapper));
|
||||
}
|
||||
Object targetValue = targetMap == null ? null : targetMap.get(entry.getKey());
|
||||
result.put(entry.getKey(), mergeForPut(entry.getValue(), targetValue, mapper));
|
||||
}
|
||||
|
||||
if (targetMap == null) {
|
||||
return result;
|
||||
}
|
||||
if (targetMap == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
targetMap.clear();
|
||||
targetMap.putAll(result);
|
||||
targetMap.clear();
|
||||
targetMap.putAll(result);
|
||||
|
||||
return targetMap;
|
||||
return targetMap;
|
||||
|
||||
} catch (UnsupportedOperationException o_O) {
|
||||
return result;
|
||||
}
|
||||
} catch (UnsupportedOperationException o_O) {
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Collection<Object> mergeCollections(PersistentProperty<?> property, Object source, Object target,
|
||||
ObjectMapper mapper) {
|
||||
private Optional<Collection<Object>> mergeCollections(PersistentProperty<?> property, Optional<Object> source,
|
||||
Optional<Object> target, ObjectMapper mapper) {
|
||||
|
||||
Collection<Object> sourceCollection = asCollection(source);
|
||||
return source.map(it -> {
|
||||
|
||||
if (sourceCollection == null) {
|
||||
return null;
|
||||
}
|
||||
Collection<Object> sourceCollection = asCollection(it);
|
||||
Collection<Object> targetCollection = asCollection(target.orElse(null));
|
||||
Collection<Object> result = targetCollection == null
|
||||
? CollectionFactory.createCollection(Collection.class, sourceCollection.size())
|
||||
: CollectionFactory.createApproximateCollection(targetCollection, sourceCollection.size());
|
||||
|
||||
Collection<Object> targetCollection = asCollection(target);
|
||||
Collection<Object> result = targetCollection == null
|
||||
? CollectionFactory.createCollection(Collection.class, sourceCollection.size())
|
||||
: CollectionFactory.createApproximateCollection(targetCollection, sourceCollection.size());
|
||||
Iterator<Object> sourceIterator = sourceCollection.iterator();
|
||||
Iterator<Object> targetIterator = targetCollection == null ? Collections.emptyIterator()
|
||||
: targetCollection.iterator();
|
||||
|
||||
Iterator<Object> sourceIterator = sourceCollection.iterator();
|
||||
Iterator<Object> targetIterator = targetCollection == null ? Collections.emptyIterator()
|
||||
: targetCollection.iterator();
|
||||
while (sourceIterator.hasNext()) {
|
||||
|
||||
while (sourceIterator.hasNext()) {
|
||||
Object sourceElement = sourceIterator.next();
|
||||
Object targetElement = targetIterator.hasNext() ? targetIterator.next() : null;
|
||||
|
||||
Object sourceElement = sourceIterator.next();
|
||||
Object targetElement = targetIterator.hasNext() ? targetIterator.next() : null;
|
||||
result.add(mergeForPut(sourceElement, targetElement, mapper));
|
||||
}
|
||||
|
||||
result.add(mergeForPut(sourceElement, targetElement, mapper));
|
||||
}
|
||||
if (targetCollection == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (targetCollection == null) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
|
||||
try {
|
||||
targetCollection.clear();
|
||||
targetCollection.addAll(result);
|
||||
|
||||
targetCollection.clear();
|
||||
targetCollection.addAll(result);
|
||||
return targetCollection;
|
||||
|
||||
return targetCollection;
|
||||
|
||||
} catch (UnsupportedOperationException o_O) {
|
||||
return result;
|
||||
}
|
||||
} catch (UnsupportedOperationException o_O) {
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Collection<Object> asCollection(Object source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
} else if (source instanceof Collection) {
|
||||
if (source instanceof Collection) {
|
||||
return (Collection<Object>) source;
|
||||
} else if (source.getClass().isArray()) {
|
||||
return Arrays.asList(ObjectUtils.toObjectArray(source));
|
||||
@@ -535,8 +532,9 @@ public class DomainObjectReader {
|
||||
* @param type can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Class<?> typeOrObject(TypeInformation<?> type) {
|
||||
return type == null ? Object.class : type.getType();
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private static Class<?> typeOrObject(Optional<TypeInformation<?>> type) {
|
||||
return type.map(it -> it.getType()).orElse((Class) Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,21 +546,21 @@ public class DomainObjectReader {
|
||||
* @param type can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static TypeInformation<?> getTypeToMap(Object value, TypeInformation<?> type) {
|
||||
private static TypeInformation<?> getTypeToMap(Object value, Optional<TypeInformation<?>> type) {
|
||||
|
||||
if (type == null) {
|
||||
type = ClassTypeInformation.OBJECT;
|
||||
}
|
||||
return type.map(it -> {
|
||||
|
||||
if (value == null) {
|
||||
return type;
|
||||
}
|
||||
if (value == null) {
|
||||
return it;
|
||||
}
|
||||
|
||||
if (Enum.class.isInstance(value)) {
|
||||
return ClassTypeInformation.from(((Enum<?>) value).getDeclaringClass());
|
||||
}
|
||||
if (Enum.class.isInstance(value)) {
|
||||
return ClassTypeInformation.from(((Enum<?>) value).getDeclaringClass());
|
||||
}
|
||||
|
||||
return value.getClass().equals(type.getType()) ? type : ClassTypeInformation.from(value.getClass());
|
||||
return value.getClass().equals(it.getType()) ? it : ClassTypeInformation.from(value.getClass());
|
||||
|
||||
}).orElse(ClassTypeInformation.OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,9 +640,9 @@ public class DomainObjectReader {
|
||||
return;
|
||||
}
|
||||
|
||||
Object sourceValue = sourceAccessor.getProperty(property);
|
||||
Object targetValue = targetAccessor.getProperty(property);
|
||||
Object result = null;
|
||||
Optional<Object> sourceValue = sourceAccessor.getProperty(property);
|
||||
Optional<Object> targetValue = targetAccessor.getProperty(property);
|
||||
Optional<?> result = Optional.empty();
|
||||
|
||||
if (property.isMap()) {
|
||||
result = mergeMaps(property, sourceValue, targetValue, mapper);
|
||||
@@ -659,4 +657,30 @@ public class DomainObjectReader {
|
||||
targetAccessor.setProperty(property, result);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T execute(SupplierWithException<T> block) {
|
||||
|
||||
try {
|
||||
return block.execute();
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
private static void execute(RunnableWithException block) {
|
||||
|
||||
try {
|
||||
block.execute();
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
interface RunnableWithException {
|
||||
void execute() throws Exception;
|
||||
}
|
||||
|
||||
interface SupplierWithException<T> {
|
||||
T execute() throws Exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -153,7 +154,7 @@ public class JacksonMappingAwareSortTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
return filteredOrders.isEmpty() ? null : new Sort(filteredOrders);
|
||||
return filteredOrders.isEmpty() ? Sort.unsorted() : Sort.by(filteredOrders);
|
||||
}
|
||||
|
||||
private String getMappedPropertyPath(PersistentEntity<?, ?> rootEntity, List<String> iteratorSource) {
|
||||
@@ -209,32 +210,28 @@ public class JacksonMappingAwareSortTranslator {
|
||||
|
||||
private final PersistentEntities persistentEntities;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final PersistentEntity<?, ?> currentType;
|
||||
private final Optional<PersistentEntity<?, ? extends PersistentProperty<?>>> currentType;
|
||||
private final MappedProperties currentProperties;
|
||||
private final WrappedProperties currentWrappedProperties;
|
||||
|
||||
private TypedSegment(TypedSegment previous, PersistentEntity<?, ?> persistentEntity) {
|
||||
private TypedSegment(TypedSegment previous,
|
||||
Optional<PersistentEntity<?, ? extends PersistentProperty<?>>> persistentEntity) {
|
||||
this(previous.persistentEntities, previous.objectMapper, persistentEntity);
|
||||
}
|
||||
|
||||
private TypedSegment(PersistentEntities persistentEntities, ObjectMapper objectMapper,
|
||||
PersistentEntity<?, ?> persistentEntity) {
|
||||
Optional<PersistentEntity<?, ? extends PersistentProperty<?>>> persistentEntity) {
|
||||
|
||||
this.persistentEntities = persistentEntities;
|
||||
this.objectMapper = objectMapper;
|
||||
this.currentType = persistentEntity;
|
||||
this.currentProperties = persistentEntity//
|
||||
.map(it -> MappedProperties.fromJacksonProperties(it, objectMapper))//
|
||||
.orElseGet(() -> MappedProperties.none());
|
||||
this.currentWrappedProperties = persistentEntity//
|
||||
.map(it -> WrappedProperties.fromJacksonProperties(persistentEntities, it, objectMapper))//
|
||||
.orElseGet(() -> WrappedProperties.none());
|
||||
|
||||
if (persistentEntity != null) {
|
||||
|
||||
this.currentProperties = MappedProperties.fromJacksonProperties(currentType, objectMapper);
|
||||
this.currentWrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, currentType,
|
||||
objectMapper);
|
||||
|
||||
} else {
|
||||
|
||||
this.currentProperties = null;
|
||||
this.currentWrappedProperties = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +250,7 @@ public class JacksonMappingAwareSortTranslator {
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null!");
|
||||
Assert.notNull(rootEntity, "PersistentEntity must not be null!");
|
||||
|
||||
return new TypedSegment(persistentEntities, objectMapper, rootEntity);
|
||||
return new TypedSegment(persistentEntities, objectMapper, Optional.of(rootEntity));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,8 +263,7 @@ public class JacksonMappingAwareSortTranslator {
|
||||
|
||||
Assert.notNull(persistentProperty, "PersistentProperty must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(persistentProperty.getType());
|
||||
return new TypedSegment(this, persistentEntity);
|
||||
return new TypedSegment(this, persistentEntities.getPersistentEntity(persistentProperty.getType()));
|
||||
}
|
||||
|
||||
private boolean hasPersistentPropertyForField(String fieldName) {
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -39,6 +43,7 @@ import com.fasterxml.jackson.databind.introspect.ClassIntrospector;
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
class MappedProperties {
|
||||
|
||||
private static final ClassIntrospector INTROSPECTOR = new BasicClassIntrospector();
|
||||
@@ -53,7 +58,7 @@ class MappedProperties {
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param description must not be {@literal null}.
|
||||
*/
|
||||
private MappedProperties(PersistentEntity<?, ?> entity, BeanDescription description) {
|
||||
private MappedProperties(PersistentEntity<?, ? extends PersistentProperty<?>> entity, BeanDescription description) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
Assert.notNull(description, "BeanDescription must not be null!");
|
||||
@@ -64,12 +69,15 @@ class MappedProperties {
|
||||
|
||||
for (BeanPropertyDefinition property : description.findProperties()) {
|
||||
|
||||
PersistentProperty<?> persistentProperty = entity.getPersistentProperty(property.getInternalName());
|
||||
Optional<? extends PersistentProperty<?>> persistentProperty = entity
|
||||
.getPersistentProperty(property.getInternalName());
|
||||
|
||||
if (persistentProperty != null) {
|
||||
propertyToFieldName.put(persistentProperty, property);
|
||||
fieldNameToProperty.put(property.getName(), persistentProperty);
|
||||
} else {
|
||||
persistentProperty.ifPresent(it -> {
|
||||
propertyToFieldName.put(it, property);
|
||||
fieldNameToProperty.put(property.getName(), it);
|
||||
});
|
||||
|
||||
if (!persistentProperty.isPresent()) {
|
||||
unmappedProperties.add(property);
|
||||
}
|
||||
}
|
||||
@@ -90,6 +98,10 @@ class MappedProperties {
|
||||
return new MappedProperties(entity, description);
|
||||
}
|
||||
|
||||
public static MappedProperties none() {
|
||||
return new MappedProperties(Collections.emptyMap(), Collections.emptyMap(), Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param property must not be {@literal null}
|
||||
* @return the mapped name for the {@link PersistentProperty}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class MappingAwareDefaultedPageableArgumentResolver implements HandlerMet
|
||||
}
|
||||
|
||||
Sort translated = translator.translateSort(pageable.getSort(), parameter, webRequest);
|
||||
pageable = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), translated);
|
||||
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), translated);
|
||||
|
||||
return new DefaultedPageable(pageable, delegate.isFallbackPageable(pageable));
|
||||
}
|
||||
|
||||
@@ -70,6 +70,6 @@ public class MappingAwarePageableArgumentResolver implements HandlerMethodArgume
|
||||
}
|
||||
|
||||
Sort translated = translator.translateSort(pageable.getSort(), methodParameter, webRequest);
|
||||
return new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), translated);
|
||||
return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), translated);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,6 @@ public class MappingAwareSortArgumentResolver implements HandlerMethodArgumentRe
|
||||
|
||||
Sort sort = delegate.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
|
||||
|
||||
return sort == null ? null : translator.translateSort(sort, methodParameter, webRequest);
|
||||
return sort.isUnsorted() ? sort : translator.translateSort(sort, methodParameter, webRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -44,16 +45,17 @@ import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.core.util.Java8PluginRegistry;
|
||||
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.mvc.ResourceProcessorInvoker;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -78,7 +80,6 @@ import com.fasterxml.jackson.databind.deser.ValueInstantiator;
|
||||
import com.fasterxml.jackson.databind.deser.std.CollectionDeserializer;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
|
||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
@@ -242,58 +243,56 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
public BeanSerializerBuilder updateBuilder(SerializationConfig config, BeanDescription beanDesc,
|
||||
BeanSerializerBuilder builder) {
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(beanDesc.getBeanClass());
|
||||
entities.getPersistentEntity(beanDesc.getBeanClass()).ifPresent(entity -> {
|
||||
|
||||
if (entity == null) {
|
||||
return builder;
|
||||
}
|
||||
List<BeanPropertyWriter> result = new ArrayList<BeanPropertyWriter>();
|
||||
|
||||
List<BeanPropertyWriter> result = new ArrayList<BeanPropertyWriter>();
|
||||
for (BeanPropertyWriter writer : builder.getProperties()) {
|
||||
|
||||
for (BeanPropertyWriter writer : builder.getProperties()) {
|
||||
Optional<? extends PersistentProperty<?>> findProperty = findProperty(writer.getName(), entity, beanDesc);
|
||||
|
||||
// Skip exported associations
|
||||
PersistentProperty<?> persistentProperty = findProperty(writer.getName(), entity, beanDesc);
|
||||
findProperty.ifPresent(it -> {
|
||||
|
||||
if (persistentProperty == null) {
|
||||
result.add(writer);
|
||||
continue;
|
||||
if (associations.isLookupType(it)) {
|
||||
|
||||
LOG.debug("Assigning lookup object serializer for {}.", it);
|
||||
writer.assignSerializer(lookupObjectSerializer);
|
||||
result.add(writer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Is there a default projection?
|
||||
|
||||
if (associations.isLinkableAssociation(it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip ids unless explicitly configured to expose
|
||||
if (it.isIdProperty() && !associations.isIdExposed(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (it.isVersionProperty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (it.isEntity() && !writer.isUnwrapping()) {
|
||||
|
||||
LOG.debug("Assigning nested entity serializer for {}.", it);
|
||||
|
||||
writer.assignSerializer(nestedEntitySerializer);
|
||||
}
|
||||
|
||||
result.add(writer);
|
||||
});
|
||||
|
||||
if (!findProperty.isPresent()) {
|
||||
result.add(writer);
|
||||
}
|
||||
}
|
||||
|
||||
if (associations.isLookupType(persistentProperty)) {
|
||||
|
||||
LOG.debug("Assigning lookup object serializer for {}.", persistentProperty);
|
||||
writer.assignSerializer(lookupObjectSerializer);
|
||||
result.add(writer);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is there a default projection?
|
||||
|
||||
if (associations.isLinkableAssociation(persistentProperty)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip ids unless explicitly configured to expose
|
||||
if (persistentProperty.isIdProperty() && !associations.isIdExposed(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (persistentProperty.isVersionProperty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (persistentProperty.isEntity() && !writer.isUnwrapping()) {
|
||||
|
||||
LOG.debug("Assigning nested entity serializer for {}.", persistentProperty);
|
||||
|
||||
writer.assignSerializer(nestedEntitySerializer);
|
||||
}
|
||||
|
||||
result.add(writer);
|
||||
}
|
||||
|
||||
builder.setProperties(result);
|
||||
builder.setProperties(result);
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -307,16 +306,12 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
* @param description the Jackson {@link BeanDescription}.
|
||||
* @return
|
||||
*/
|
||||
private PersistentProperty<?> findProperty(String finalName, PersistentEntity<?, ?> entity,
|
||||
BeanDescription description) {
|
||||
private Optional<? extends PersistentProperty<?>> findProperty(String finalName,
|
||||
PersistentEntity<?, ? extends PersistentProperty<?>> entity, BeanDescription description) {
|
||||
|
||||
for (BeanPropertyDefinition definition : description.findProperties()) {
|
||||
if (definition.getName().equals(finalName)) {
|
||||
return entity.getPersistentProperty(definition.getInternalName());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return description.findProperties().stream()//
|
||||
.filter(it -> it.getName().equals(finalName))//
|
||||
.findFirst().flatMap(it -> entity.getPersistentProperty(it.getInternalName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +385,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
|
||||
private Resource<Object> toResource(Object value) {
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(value.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(value.getClass());
|
||||
|
||||
return invoker.invokeProcessorsFor(PersistentEntityResource.build(value, entity).//
|
||||
withEmbedded(assembler.getEmbeddedResources(value)).//
|
||||
@@ -422,37 +417,37 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
BeanDeserializerBuilder builder) {
|
||||
|
||||
Iterator<SettableBeanProperty> properties = builder.getProperties();
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(beanDesc.getBeanClass());
|
||||
|
||||
if (entity == null) {
|
||||
return builder;
|
||||
}
|
||||
entities.getPersistentEntity(beanDesc.getBeanClass()).ifPresent(entity -> {
|
||||
|
||||
while (properties.hasNext()) {
|
||||
while (properties.hasNext()) {
|
||||
|
||||
SettableBeanProperty property = properties.next();
|
||||
PersistentProperty<?> persistentProperty = entity.getPersistentProperty(property.getName());
|
||||
SettableBeanProperty property = properties.next();
|
||||
|
||||
if (associationLinks.isLookupType(persistentProperty)) {
|
||||
entity.getPersistentProperty(property.getName()).ifPresent(persistentProperty -> {
|
||||
|
||||
RepositoryInvokingDeserializer repositoryInvokingDeserializer = new RepositoryInvokingDeserializer(factory,
|
||||
persistentProperty);
|
||||
JsonDeserializer<?> deserializer = wrapIfCollection(persistentProperty, repositoryInvokingDeserializer,
|
||||
config);
|
||||
if (associationLinks.isLookupType(persistentProperty)) {
|
||||
|
||||
builder.addOrReplaceProperty(property.withValueDeserializer(deserializer), false);
|
||||
continue;
|
||||
RepositoryInvokingDeserializer repositoryInvokingDeserializer = new RepositoryInvokingDeserializer(
|
||||
factory, persistentProperty);
|
||||
JsonDeserializer<?> deserializer = wrapIfCollection(persistentProperty, repositoryInvokingDeserializer,
|
||||
config);
|
||||
|
||||
builder.addOrReplaceProperty(property.withValueDeserializer(deserializer), false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!associationLinks.isLinkableAssociation(persistentProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UriStringDeserializer uriStringDeserializer = new UriStringDeserializer(persistentProperty, converter);
|
||||
JsonDeserializer<?> deserializer = wrapIfCollection(persistentProperty, uriStringDeserializer, config);
|
||||
|
||||
builder.addOrReplaceProperty(property.withValueDeserializer(deserializer), false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!associationLinks.isLinkableAssociation(persistentProperty)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UriStringDeserializer uriStringDeserializer = new UriStringDeserializer(persistentProperty, converter);
|
||||
JsonDeserializer<?> deserializer = wrapIfCollection(persistentProperty, uriStringDeserializer, config);
|
||||
|
||||
builder.addOrReplaceProperty(property.withValueDeserializer(deserializer), false);
|
||||
}
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -775,7 +770,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
public static class LookupObjectSerializer extends ToStringSerializer {
|
||||
|
||||
private static final long serialVersionUID = -3033458643050330913L;
|
||||
private final PluginRegistry<EntityLookup<?>, Class<?>> lookups;
|
||||
private final Java8PluginRegistry<EntityLookup<?>, Class<?>> lookups;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -799,11 +794,13 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getLookupKey(Object value) {
|
||||
|
||||
EntityLookup<Object> lookup = (EntityLookup<Object>) lookups.getPluginFor(value.getClass());
|
||||
return lookup.getResourceIdentifier(value).toString();
|
||||
Optional<EntityLookup<Object>> map = lookups.getPluginFor(value.getClass()).map(CastUtils::cast);
|
||||
|
||||
return map
|
||||
.orElseThrow(() -> new IllegalArgumentException("No EntityLookup found for " + value.getClass().getName()))
|
||||
.getResourceIdentifier(value).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -53,6 +54,7 @@ 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.Associations;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -78,10 +80,10 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
private final Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
private final Associations associations;
|
||||
private final PersistentEntities entities;
|
||||
private final MessageSourceAccessor accessor;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final RepositoryRestConfiguration configuration;
|
||||
private final ValueTypeSchemaPropertyCustomizerFactory customizerFactory;
|
||||
private final MessageResolver resolver;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityToJsonSchemaConverter} for the given {@link PersistentEntities} and
|
||||
@@ -105,10 +107,10 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
|
||||
this.entities = entities;
|
||||
this.associations = associations;
|
||||
this.accessor = accessor;
|
||||
this.objectMapper = objectMapper;
|
||||
this.configuration = configuration;
|
||||
this.customizerFactory = customizerFactory;
|
||||
this.resolver = new DefaultMessageResolver(accessor, configuration);
|
||||
|
||||
for (TypeInformation<?> domainType : entities.getManagedTypes()) {
|
||||
convertiblePairs.add(new ConvertiblePair(domainType.getType(), JsonSchema.class));
|
||||
@@ -151,121 +153,116 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
@Override
|
||||
public JsonSchema convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
final PersistentEntity<?, ?> persistentEntity = entities.getPersistentEntity((Class<?>) source);
|
||||
final PersistentEntity<?, ?> persistentEntity = entities.getRequiredPersistentEntity((Class<?>) source);
|
||||
final ResourceMetadata metadata = associations.getMappings().getMetadataFor(persistentEntity.getType());
|
||||
|
||||
Definitions definitions = new Definitions();
|
||||
List<AbstractJsonSchemaProperty<?>> propertiesFor = getPropertiesFor(persistentEntity.getType(), metadata,
|
||||
definitions);
|
||||
|
||||
String title = resolveMessageWithDefault(new ResolvableType(persistentEntity.getType()));
|
||||
String title = resolver.resolveWithDefault(new ResolvableType(persistentEntity.getType()));
|
||||
|
||||
return new JsonSchema(title, resolveMessage(metadata.getItemResourceDescription()), propertiesFor, definitions);
|
||||
return new JsonSchema(title, resolver.resolve(metadata.getItemResourceDescription()), propertiesFor, definitions);
|
||||
}
|
||||
|
||||
private List<AbstractJsonSchemaProperty<?>> getPropertiesFor(Class<?> type, final ResourceMetadata metadata,
|
||||
final Definitions definitions) {
|
||||
|
||||
final PersistentEntity<?, ?> entity = entities.getPersistentEntity(type);
|
||||
final JacksonMetadata jackson = new JacksonMetadata(objectMapper, type);
|
||||
return entities.getPersistentEntity(type).map(entity -> {
|
||||
|
||||
if (entity == null) {
|
||||
return Collections.<AbstractJsonSchemaProperty<?>> emptyList();
|
||||
}
|
||||
final JacksonMetadata jackson = new JacksonMetadata(objectMapper, type);
|
||||
JsonSchemaPropertyRegistrar registrar = new JsonSchemaPropertyRegistrar(jackson);
|
||||
|
||||
JsonSchemaPropertyRegistrar registrar = new JsonSchemaPropertyRegistrar(jackson);
|
||||
for (BeanPropertyDefinition definition : jackson) {
|
||||
|
||||
for (BeanPropertyDefinition definition : jackson) {
|
||||
JacksonProperty jacksonProperty = new JacksonProperty(jackson,
|
||||
entity.getPersistentProperty(definition.getInternalName()), definition);
|
||||
|
||||
PersistentProperty<?> persistentProperty = entity.getPersistentProperty(definition.getInternalName());
|
||||
Optional<? extends PersistentProperty<?>> prop = entity.getPersistentProperty(definition.getInternalName());
|
||||
|
||||
// First pass, early drops to avoid unnecessary calculation
|
||||
if (persistentProperty != null) {
|
||||
// First pass, early drops to avoid unnecessary calculation
|
||||
if (prop.isPresent()) {
|
||||
|
||||
if (persistentProperty.isIdProperty() && !configuration.isIdExposedFor(type)) {
|
||||
continue;
|
||||
}
|
||||
PersistentProperty<?> persistentProperty = prop.get();
|
||||
|
||||
if (persistentProperty.isVersionProperty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!definition.couldSerialize()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
AnnotatedMember primaryMember = definition.getPrimaryMember();
|
||||
|
||||
if (primaryMember == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeInformation<?> propertyType = persistentProperty == null
|
||||
? ClassTypeInformation.from(primaryMember.getRawType()) : persistentProperty.getTypeInformation();
|
||||
TypeInformation<?> actualPropertyType = propertyType.getActualType();
|
||||
Class<?> rawPropertyType = propertyType.getType();
|
||||
|
||||
JsonSchemaFormat format = configuration.getMetadataConfiguration().getSchemaFormatFor(rawPropertyType);
|
||||
ResourceDescription description = persistentProperty == null
|
||||
? jackson.getFallbackDescription(metadata, definition) : getDescriptionFor(persistentProperty, metadata);
|
||||
JsonSchemaProperty property = getSchemaProperty(definition, propertyType, description);
|
||||
|
||||
boolean isSyntheticProperty = persistentProperty == null;
|
||||
boolean isNotWritable = !isSyntheticProperty && !persistentProperty.isWritable();
|
||||
boolean isJacksonReadOnly = !isSyntheticProperty && jackson.isReadOnly(persistentProperty);
|
||||
|
||||
if (isSyntheticProperty || isNotWritable || isJacksonReadOnly) {
|
||||
property = property.withReadOnly();
|
||||
}
|
||||
|
||||
if (format != null) {
|
||||
|
||||
// Types with explicitly registered format -> value object with format
|
||||
registrar.register(property.withFormat(format), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
Pattern pattern = configuration.getMetadataConfiguration().getPatternFor(rawPropertyType);
|
||||
|
||||
if (pattern != null) {
|
||||
registrar.register(property.withPattern(pattern), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (jackson.isValueType()) {
|
||||
registrar.register(property.with(STRING_TYPE_INFORMATION), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (persistentProperty == null) {
|
||||
registrar.register(property, actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (configuration.isLookupType(persistentProperty.getActualType())) {
|
||||
registrar.register(property.with(propertyType), actualPropertyType);
|
||||
} else if (associations.isLinkableAssociation(persistentProperty)) {
|
||||
registrar.register(property.asAssociation(), null);
|
||||
} else {
|
||||
|
||||
if (persistentProperty.isEntity()) {
|
||||
|
||||
if (!definitions.hasDefinitionFor(propertyType)) {
|
||||
definitions.addDefinition(propertyType,
|
||||
new Item(propertyType, getNestedPropertiesFor(persistentProperty, definitions)));
|
||||
if (persistentProperty.isIdProperty() && !configuration.isIdExposedFor(type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
registrar.register(property.with(propertyType, Definitions.getReference(propertyType)), actualPropertyType);
|
||||
if (persistentProperty.isVersionProperty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
registrar.register(property.with(propertyType), actualPropertyType);
|
||||
if (!definition.couldSerialize()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registrar.getProperties();
|
||||
AnnotatedMember primaryMember = definition.getPrimaryMember();
|
||||
|
||||
if (primaryMember == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeInformation<?> propertyType = jacksonProperty.getPropertyType();
|
||||
TypeInformation<?> actualPropertyType = propertyType.getActualType();
|
||||
Class<?> rawPropertyType = propertyType.getType();
|
||||
|
||||
JsonSchemaFormat format = configuration.getMetadataConfiguration().getSchemaFormatFor(rawPropertyType);
|
||||
|
||||
ResourceDescription description = prop.map(it -> getDescriptionFor(it, metadata))
|
||||
.orElseGet(() -> jackson.getFallbackDescription(metadata, definition));
|
||||
JsonSchemaProperty property = jacksonProperty.getSchemaProperty(description, resolver);
|
||||
|
||||
if (format != null) {
|
||||
|
||||
// Types with explicitly registered format -> value object with format
|
||||
registrar.register(property.withFormat(format), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
Pattern pattern = configuration.getMetadataConfiguration().getPatternFor(rawPropertyType);
|
||||
|
||||
if (pattern != null) {
|
||||
registrar.register(property.withPattern(pattern), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (jackson.isValueType()) {
|
||||
registrar.register(property.with(STRING_TYPE_INFORMATION), actualPropertyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
Optionals.ifPresentOrElse(prop, it -> {
|
||||
|
||||
if (configuration.isLookupType(it.getActualType())) {
|
||||
registrar.register(property.with(propertyType), actualPropertyType);
|
||||
} else if (associations.isLinkableAssociation(it)) {
|
||||
registrar.register(property.asAssociation(), null);
|
||||
} else {
|
||||
|
||||
if (it.isEntity()) {
|
||||
|
||||
if (!definitions.hasDefinitionFor(propertyType)) {
|
||||
definitions.addDefinition(propertyType,
|
||||
new Item(propertyType, getNestedPropertiesFor(it, definitions)));
|
||||
}
|
||||
|
||||
registrar.register(property.with(propertyType, Definitions.getReference(propertyType)),
|
||||
actualPropertyType);
|
||||
|
||||
} else {
|
||||
|
||||
registrar.register(property.with(propertyType), actualPropertyType);
|
||||
}
|
||||
}
|
||||
|
||||
}, () -> registrar.register(property, actualPropertyType));
|
||||
}
|
||||
|
||||
return registrar.getProperties();
|
||||
|
||||
}).orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private Collection<AbstractJsonSchemaProperty<?>> getNestedPropertiesFor(PersistentProperty<?> property,
|
||||
@@ -278,25 +275,25 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
return getPropertiesFor(property.getActualType(),
|
||||
associations.getMappings().getMetadataFor(property.getActualType()), descriptors);
|
||||
}
|
||||
|
||||
private JsonSchemaProperty getSchemaProperty(BeanPropertyDefinition definition, TypeInformation<?> type,
|
||||
ResourceDescription description) {
|
||||
|
||||
String name = definition.getName();
|
||||
String title = resolveMessageWithDefault(new ResolvableProperty(definition));
|
||||
String resolvedDescription = resolveMessage(description);
|
||||
boolean required = definition.isRequired();
|
||||
Class<?> rawType = type.getType();
|
||||
|
||||
if (!rawType.isEnum()) {
|
||||
return new JsonSchemaProperty(name, title, resolvedDescription, required).with(type);
|
||||
}
|
||||
|
||||
String message = resolveMessage(new DefaultMessageSourceResolvable(description.getMessage()));
|
||||
|
||||
return new EnumProperty(name, title, rawType,
|
||||
description.getDefaultMessage().equals(resolvedDescription) ? message : resolvedDescription, required);
|
||||
}
|
||||
//
|
||||
// private JsonSchemaProperty getSchemaProperty(BeanPropertyDefinition definition, TypeInformation<?> type,
|
||||
// ResourceDescription description) {
|
||||
//
|
||||
// String name = definition.getName();
|
||||
// String title = resolver.resolveWithDefault(new ResolvableProperty(definition));
|
||||
// String resolvedDescription = resolver.resolve(description);
|
||||
// boolean required = definition.isRequired();
|
||||
// Class<?> rawType = type.getType();
|
||||
//
|
||||
// if (!rawType.isEnum()) {
|
||||
// return new JsonSchemaProperty(name, title, resolvedDescription, required).with(type);
|
||||
// }
|
||||
//
|
||||
// String message = resolver.resolve(new DefaultMessageSourceResolvable(description.getMessage()));
|
||||
//
|
||||
// return new EnumProperty(name, title, rawType,
|
||||
// description.getDefaultMessage().equals(resolvedDescription) ? message : resolvedDescription, required);
|
||||
// }
|
||||
|
||||
private ResourceDescription getDescriptionFor(PersistentProperty<?> property, ResourceMetadata metadata) {
|
||||
|
||||
@@ -304,28 +301,6 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
return propertyMapping.getDescription();
|
||||
}
|
||||
|
||||
private String resolveMessageWithDefault(MessageSourceResolvable resolvable) {
|
||||
return resolveMessage(new DefaultingMessageSourceResolvable(resolvable));
|
||||
}
|
||||
|
||||
private String resolveMessage(MessageSourceResolvable resolvable) {
|
||||
|
||||
if (resolvable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return accessor.getMessage(resolvable);
|
||||
} catch (NoSuchMessageException o_O) {
|
||||
|
||||
if (configuration.getMetadataConfiguration().omitUnresolvableDescriptionKeys()) {
|
||||
return null;
|
||||
} else {
|
||||
throw o_O;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to register {@link JsonSchemaProperty} instances after post-processing them.
|
||||
*
|
||||
@@ -407,6 +382,148 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BeanPropertyDefinition} that can be resolved via a {@link MessageSource}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.4.1
|
||||
*/
|
||||
private static class ResolvableProperty extends DefaultMessageSourceResolvable {
|
||||
|
||||
private static final long serialVersionUID = -5603381674553244480L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResolvableProperty} for the given {@link BeanPropertyDefinition}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public ResolvableProperty(BeanPropertyDefinition property) {
|
||||
super(getCodes(property));
|
||||
}
|
||||
|
||||
private static String[] getCodes(BeanPropertyDefinition property) {
|
||||
|
||||
Assert.notNull(property, "BeanPropertyDefinition must not be null!");
|
||||
|
||||
Class<?> owner = property.getPrimaryMember().getDeclaringClass();
|
||||
|
||||
String propertyTitle = property.getInternalName().concat("._title");
|
||||
String localName = owner.getSimpleName().concat(".").concat(propertyTitle);
|
||||
String fullName = owner.getName().concat(".").concat(propertyTitle);
|
||||
|
||||
return new String[] { fullName, localName, propertyTitle };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type whose title can be resolved through a {@link MessageSource}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.4.1
|
||||
*/
|
||||
private static class ResolvableType extends DefaultMessageSourceResolvable {
|
||||
|
||||
private static final long serialVersionUID = -7199875272753949857L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResolvableType} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public ResolvableType(Class<?> type) {
|
||||
super(getTitleCodes(type));
|
||||
}
|
||||
|
||||
private static String[] getTitleCodes(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
return new String[] { type.getName().concat("._title"), type.getSimpleName().concat("._title") };
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class JacksonProperty {
|
||||
|
||||
private final JacksonMetadata metadata;
|
||||
private final Optional<? extends PersistentProperty<?>> property;
|
||||
private final BeanPropertyDefinition definition;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public TypeInformation<?> getPropertyType() {
|
||||
return property.map(it -> (TypeInformation) it.getTypeInformation())
|
||||
.orElseGet(() -> ClassTypeInformation.from(definition.getPrimaryMember().getRawType()));
|
||||
}
|
||||
|
||||
public JsonSchemaProperty getSchemaProperty(ResourceDescription description, MessageResolver resolver) {
|
||||
|
||||
JsonSchemaProperty result = getSchemaProperty(definition, getPropertyType(), description, resolver);
|
||||
|
||||
boolean isSyntheticProperty = !property.isPresent();
|
||||
boolean isNotWritable = property.map(it -> !it.isWritable()).orElse(false);
|
||||
boolean isJacksonReadOnly = property.map(it -> metadata.isReadOnly(it)).orElse(false);
|
||||
|
||||
if (isSyntheticProperty || isNotWritable || isJacksonReadOnly) {
|
||||
result = result.withReadOnly();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonSchemaProperty getSchemaProperty(BeanPropertyDefinition definition, TypeInformation<?> type,
|
||||
ResourceDescription description, MessageResolver resolver) {
|
||||
|
||||
String name = definition.getName();
|
||||
String title = resolver.resolveWithDefault(new ResolvableProperty(definition));
|
||||
String resolvedDescription = resolver.resolve(description);
|
||||
boolean required = definition.isRequired();
|
||||
Class<?> rawType = type.getType();
|
||||
|
||||
if (!rawType.isEnum()) {
|
||||
return new JsonSchemaProperty(name, title, resolvedDescription, required).with(type);
|
||||
}
|
||||
|
||||
String message = resolver.resolve(new DefaultMessageSourceResolvable(description.getMessage()));
|
||||
|
||||
return new EnumProperty(name, title, rawType,
|
||||
description.getDefaultMessage().equals(resolvedDescription) ? message : resolvedDescription, required);
|
||||
}
|
||||
}
|
||||
|
||||
private interface MessageResolver {
|
||||
|
||||
String resolve(MessageSourceResolvable resolvable);
|
||||
|
||||
default String resolveWithDefault(MessageSourceResolvable resolvable) {
|
||||
return resolve(new DefaultingMessageSourceResolvable(resolvable));
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class DefaultMessageResolver implements MessageResolver {
|
||||
|
||||
private final MessageSourceAccessor accessor;
|
||||
private final RepositoryRestConfiguration configuration;
|
||||
|
||||
public String resolve(MessageSourceResolvable resolvable) {
|
||||
|
||||
if (resolvable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return accessor.getMessage(resolvable);
|
||||
} catch (NoSuchMessageException o_O) {
|
||||
|
||||
if (configuration.getMetadataConfiguration().omitUnresolvableDescriptionKeys()) {
|
||||
return null;
|
||||
} else {
|
||||
throw o_O;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message source resolvable that defaults the messages to the last segment of the dot-separated code in case the
|
||||
* configured delegate doesn't return a default message itself.
|
||||
@@ -468,64 +585,4 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
.collectionToDelimitedString(Arrays.asList(SPLIT_CAMEL_CASE.split(tail)), " ").toLowerCase(Locale.US));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BeanPropertyDefinition} that can be resolved via a {@link MessageSource}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.4.1
|
||||
*/
|
||||
private static class ResolvableProperty extends DefaultMessageSourceResolvable {
|
||||
|
||||
private static final long serialVersionUID = -5603381674553244480L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResolvableProperty} for the given {@link BeanPropertyDefinition}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public ResolvableProperty(BeanPropertyDefinition property) {
|
||||
super(getCodes(property));
|
||||
}
|
||||
|
||||
private static String[] getCodes(BeanPropertyDefinition property) {
|
||||
|
||||
Assert.notNull(property, "BeanPropertyDefinition must not be null!");
|
||||
|
||||
Class<?> owner = property.getPrimaryMember().getDeclaringClass();
|
||||
|
||||
String propertyTitle = property.getInternalName().concat("._title");
|
||||
String localName = owner.getSimpleName().concat(".").concat(propertyTitle);
|
||||
String fullName = owner.getName().concat(".").concat(propertyTitle);
|
||||
|
||||
return new String[] { fullName, localName, propertyTitle };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type whose title can be resolved through a {@link MessageSource}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.4.1
|
||||
*/
|
||||
private static class ResolvableType extends DefaultMessageSourceResolvable {
|
||||
|
||||
private static final long serialVersionUID = -7199875272753949857L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResolvableType} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public ResolvableType(Class<?> type) {
|
||||
super(getTitleCodes(type));
|
||||
}
|
||||
|
||||
private static String[] getTitleCodes(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
return new String[] { type.getName().concat("._title"), type.getSimpleName().concat("._title") };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,12 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
@@ -81,6 +83,10 @@ class WrappedProperties {
|
||||
return new WrappedProperties(resolver.findUnwrappedPropertyPaths(entity.getType()));
|
||||
}
|
||||
|
||||
public static WrappedProperties none() {
|
||||
return new WrappedProperties(Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldName must not be empty or {@literal null}.
|
||||
* @return {@literal true} if the field name resolves to a {@literal PersistentProperty}.
|
||||
@@ -132,28 +138,28 @@ class WrappedProperties {
|
||||
private Map<String, List<PersistentProperty<?>>> findUnwrappedPropertyPaths(Class<?> type,
|
||||
NameTransformer nameTransformer, boolean considerRegularProperties) {
|
||||
|
||||
PersistentEntity<?, ?> entity = persistentEntities.getPersistentEntity(type);
|
||||
return persistentEntities.getPersistentEntity(type).map(entity -> {
|
||||
|
||||
if (entity == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, List<PersistentProperty<?>>> mapping = new HashMap<String, List<PersistentProperty<?>>>();
|
||||
|
||||
Map<String, List<PersistentProperty<?>>> mapping = new HashMap<String, List<PersistentProperty<?>>>();
|
||||
for (BeanPropertyDefinition property : getMappedProperties(entity)) {
|
||||
|
||||
for (BeanPropertyDefinition property : getMappedProperties(entity)) {
|
||||
Optionals.ifAllPresent(entity.getPersistentProperty(property.getInternalName()), //
|
||||
findAnnotatedMember(property), //
|
||||
(prop, member) -> {
|
||||
|
||||
AnnotatedMember annotatedMember = findAnnotatedMember(property);
|
||||
PersistentProperty<?> persistentProperty = entity.getPersistentProperty(property.getInternalName());
|
||||
|
||||
if (isJsonUnwrapped(annotatedMember)) {
|
||||
mapping.putAll(findUnwrappedPropertyPaths(nameTransformer, annotatedMember, persistentProperty));
|
||||
} else if (considerRegularProperties) {
|
||||
mapping.put(nameTransformer.transform(property.getName()),
|
||||
Collections.<PersistentProperty<?>> singletonList(persistentProperty));
|
||||
if (isJsonUnwrapped(member)) {
|
||||
mapping.putAll(findUnwrappedPropertyPaths(nameTransformer, member, prop));
|
||||
} else if (considerRegularProperties) {
|
||||
mapping.put(nameTransformer.transform(property.getName()),
|
||||
Collections.<PersistentProperty<?>> singletonList(prop));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
return mapping;
|
||||
|
||||
}).orElse(Collections.emptyMap());
|
||||
}
|
||||
|
||||
private Map<String, List<PersistentProperty<?>>> findUnwrappedPropertyPaths(NameTransformer nameTransformer,
|
||||
@@ -187,13 +193,9 @@ class WrappedProperties {
|
||||
|
||||
for (BeanPropertyDefinition property : properties) {
|
||||
|
||||
AnnotatedMember annotatedMember = findAnnotatedMember(property);
|
||||
|
||||
if (annotatedMember == null || entity.getPersistentProperty(property.getInternalName()) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
withInternalName.add(property);
|
||||
Optionals.ifAllPresent(findAnnotatedMember(property), //
|
||||
entity.getPersistentProperty(property.getInternalName()), //
|
||||
(member, prop) -> withInternalName.add(property));
|
||||
}
|
||||
|
||||
return withInternalName;
|
||||
@@ -204,21 +206,21 @@ class WrappedProperties {
|
||||
mapper.getDeserializationConfig());
|
||||
}
|
||||
|
||||
private static AnnotatedMember findAnnotatedMember(BeanPropertyDefinition property) {
|
||||
private static Optional<AnnotatedMember> findAnnotatedMember(BeanPropertyDefinition property) {
|
||||
|
||||
if (property.getPrimaryMember() != null) {
|
||||
return property.getPrimaryMember();
|
||||
return Optional.of(property.getPrimaryMember());
|
||||
}
|
||||
|
||||
if (property.getGetter() != null) {
|
||||
return property.getGetter();
|
||||
return Optional.of(property.getGetter());
|
||||
}
|
||||
|
||||
if (property.getSetter() != null) {
|
||||
return property.getSetter();
|
||||
return Optional.of(property.getSetter());
|
||||
}
|
||||
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean isJsonUnwrapped(AnnotatedMember primaryMember) {
|
||||
|
||||
@@ -89,11 +89,14 @@ public class Associations {
|
||||
/**
|
||||
* Returns whether the type of the given {@link PersistentProperty} is configured as lookup type.
|
||||
*
|
||||
* @param property can be {@literal null}.
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isLookupType(PersistentProperty<?> property) {
|
||||
return property == null ? false : config.isLookupType(property.getActualType());
|
||||
|
||||
Assert.notNull(property, "Persistent property must not be null!");
|
||||
|
||||
return config.isLookupType(property.getActualType());
|
||||
}
|
||||
|
||||
public boolean isIdExposed(PersistentEntity<?, ?> entity) {
|
||||
@@ -116,12 +119,14 @@ public class Associations {
|
||||
/**
|
||||
* Returns whether the given property is an association that is linkable.
|
||||
*
|
||||
* @param property can be {@literal null}.
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isLinkableAssociation(PersistentProperty<?> property) {
|
||||
|
||||
if (property == null || !property.isAssociation() || config.isLookupType(property.getActualType())) {
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
if (!property.isAssociation() || config.isLookupType(property.getActualType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,8 +90,6 @@ public class LinkCollector {
|
||||
Assert.notNull(object, "Object must not be null!");
|
||||
Assert.notNull(existingLinks, "Existing links must not be null!");
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(object.getClass());
|
||||
|
||||
Links links = new Links(existingLinks);
|
||||
Link selfLink = createSelfLink(object, links);
|
||||
|
||||
@@ -102,7 +100,7 @@ public class LinkCollector {
|
||||
Path path = new Path(selfLink.expand().getHref());
|
||||
|
||||
LinkCollectingAssociationHandler handler = new LinkCollectingAssociationHandler(entities, path, associationLinks);
|
||||
entity.doWithAssociations(handler);
|
||||
entities.getRequiredPersistentEntity(object.getClass()).doWithAssociations(handler);
|
||||
|
||||
List<Link> result = new ArrayList<Link>(existingLinks);
|
||||
result.addAll(handler.getLinks());
|
||||
@@ -112,7 +110,7 @@ public class LinkCollector {
|
||||
|
||||
public Links getLinksForNested(Object object, List<Link> existing) {
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(object.getClass());
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(object.getClass());
|
||||
|
||||
NestedLinkCollectingAssociationHandler handler = new NestedLinkCollectingAssociationHandler(links,
|
||||
entity.getPropertyAccessor(object), associationLinks);
|
||||
@@ -217,19 +215,17 @@ public class LinkCollector {
|
||||
}
|
||||
|
||||
PersistentProperty<?> property = association.getInverse();
|
||||
Object value = accessor.getProperty(property);
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
accessor.getProperty(property).ifPresent(it -> {
|
||||
|
||||
ResourceMetadata metadata = associations.getMappings().getMetadataFor(property.getOwner().getType());
|
||||
ResourceMapping propertyMapping = metadata.getMappingFor(property);
|
||||
ResourceMetadata metadata = associations.getMappings().getMetadataFor(property.getOwner().getType());
|
||||
ResourceMapping propertyMapping = metadata.getMappingFor(property);
|
||||
|
||||
for (Object element : asCollection(value)) {
|
||||
if (element != null)
|
||||
links.add(getLinkFor(element, propertyMapping));
|
||||
}
|
||||
for (Object element : asCollection(it)) {
|
||||
if (element != null)
|
||||
links.add(getLinkFor(element, propertyMapping));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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,6 +24,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
@@ -64,8 +65,8 @@ public class NestedLinkCollectingAssociationHandler implements SimpleAssociation
|
||||
|
||||
for (Object element : (Collection<?>) propertyValue) {
|
||||
|
||||
IdentifierAccessor identifierAccessor = entities.getPersistentEntity(element.getClass())
|
||||
.getIdentifierAccessor(element);
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(element.getClass());
|
||||
IdentifierAccessor identifierAccessor = entity.getIdentifierAccessor(element);
|
||||
|
||||
links.add(entityLinks.linkForSingleResource(element.getClass(), identifierAccessor.getIdentifier())
|
||||
.withRel(propertyMapping.getRel()));
|
||||
@@ -73,8 +74,8 @@ public class NestedLinkCollectingAssociationHandler implements SimpleAssociation
|
||||
}
|
||||
|
||||
} else {
|
||||
IdentifierAccessor identifierAccessor = entities.getPersistentEntity(propertyValue.getClass())
|
||||
.getIdentifierAccessor(propertyValue);
|
||||
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(propertyValue.getClass());
|
||||
IdentifierAccessor identifierAccessor = entity.getIdentifierAccessor(propertyValue);
|
||||
|
||||
links.add(entityLinks.linkForSingleResource(propertyValue.getClass(), identifierAccessor.getIdentifier())
|
||||
.withRel(propertyMapping.getRel()));
|
||||
|
||||
@@ -19,12 +19,12 @@ import java.io.Serializable;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.util.Java8PluginRegistry;
|
||||
import org.springframework.data.rest.webmvc.BaseUri;
|
||||
import org.springframework.data.rest.webmvc.config.ResourceMetadataHandlerMethodArgumentResolver;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConverter;
|
||||
import org.springframework.data.rest.webmvc.util.UriUtils;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -39,7 +39,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
*/
|
||||
public class BackendIdHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private final PluginRegistry<BackendIdConverter, Class<?>> idConverters;
|
||||
private final Java8PluginRegistry<BackendIdConverter, Class<?>> idConverters;
|
||||
private final ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver;
|
||||
private final BaseUri baseUri;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class BackendIdHandlerMethodArgumentResolver implements HandlerMethodArgu
|
||||
* @param resourceMetadataResolver the resolver to obtain {@link ResourceMetadata} from, must not be {@literal null}.
|
||||
* @param baseUri must not be {@literal null}.
|
||||
*/
|
||||
public BackendIdHandlerMethodArgumentResolver(PluginRegistry<BackendIdConverter, Class<?>> idConverters,
|
||||
public BackendIdHandlerMethodArgumentResolver(Java8PluginRegistry<BackendIdConverter, Class<?>> idConverters,
|
||||
ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver, BaseUri baseUri) {
|
||||
|
||||
Assert.notNull(idConverters, "Id converters must not be null!");
|
||||
@@ -95,7 +95,8 @@ public class BackendIdHandlerMethodArgumentResolver implements HandlerMethodArgu
|
||||
throw new IllegalArgumentException("Could not obtain ResourceMetadata for request " + request);
|
||||
}
|
||||
|
||||
BackendIdConverter pluginFor = idConverters.getPluginFor(metadata.getDomainType(), DefaultIdConverter.INSTANCE);
|
||||
BackendIdConverter pluginFor = idConverters.getPluginFor(metadata.getDomainType())
|
||||
.orElse(DefaultIdConverter.INSTANCE);
|
||||
String lookupPath = baseUri.getRepositoryLookupPath(request);
|
||||
return pluginFor.fromRequestId(UriUtils.findMappingVariable("id", parameter.getMethod(), lookupPath),
|
||||
metadata.getDomainType());
|
||||
|
||||
@@ -17,18 +17,23 @@ package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A value object to represent ETags.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public final class ETag {
|
||||
|
||||
public static final ETag NO_ETAG = new ETag(null);
|
||||
@@ -48,21 +53,28 @@ public final class ETag {
|
||||
* Creates a new {@link ETag} for the given {@link String} value. Falls back to {@link #NO_ETAG} in case
|
||||
* {@literal null} is provided.
|
||||
*
|
||||
* @param value the source ETag value, can be {@literal null}.
|
||||
* @param value the source ETag value, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ETag from(String value) {
|
||||
return value == null ? NO_ETAG : new ETag(value);
|
||||
return new ETag(value);
|
||||
}
|
||||
|
||||
public static ETag from(Optional<String> value) {
|
||||
return value.map(ETag::new).orElse(NO_ETAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ETag} for the given {@link PersistentEntityResource}.
|
||||
*
|
||||
* @param resource can be {@literal null}.
|
||||
* @param resource must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ETag from(PersistentEntityResource resource) {
|
||||
return resource == null ? NO_ETAG : from(resource.getPersistentEntity(), resource.getContent());
|
||||
|
||||
Assert.notNull(resource, "PersistentEntityResource must not be null!");
|
||||
|
||||
return from(resource.getPersistentEntity(), resource.getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,8 +84,8 @@ public final class ETag {
|
||||
* @param bean must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ETag from(PersistentEntity<?, ?> entity, Object bean) {
|
||||
return from(getVersionInformation(entity, bean));
|
||||
public static ETag from(PersistentEntity<?, ? extends PersistentProperty<?>> entity, Object bean) {
|
||||
return getVersionInformation(entity, bean).map(ETag::from).orElse(NO_ETAG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,35 +154,6 @@ public final class ETag {
|
||||
return value == null ? null : "\"".concat(value).concat("\"");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof ETag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ETag that = (ETag) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.value, that.value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quoted version property of a domain object, returns null if it doesn't contains the property
|
||||
*
|
||||
@@ -178,17 +161,16 @@ public final class ETag {
|
||||
* @param bean
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static String getVersionInformation(PersistentEntity entity, Object bean) {
|
||||
private static Optional<String> getVersionInformation(PersistentEntity<?, ? extends PersistentProperty<?>> entity,
|
||||
Object bean) {
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
Assert.notNull(bean, "Target bean must not be null!");
|
||||
|
||||
if (!entity.hasVersionProperty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(bean);
|
||||
return accessor.getProperty(entity.getVersionProperty()).toString();
|
||||
|
||||
return entity.getVersionProperty()//
|
||||
.flatMap(it -> accessor.getProperty(it))//
|
||||
.map(Object::toString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.springframework.http.HttpHeaders.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -48,6 +50,6 @@ public class ETagArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
@Override
|
||||
public ETag resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
return ETag.from(webRequest.getHeader(IF_MATCH));
|
||||
return ETag.from(Optional.ofNullable(webRequest.getHeader(IF_MATCH)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.springframework.data.rest.core.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.SearchResourceMappings;
|
||||
import org.springframework.data.rest.core.util.Java8PluginRegistry;
|
||||
import org.springframework.data.rest.webmvc.BaseUri;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
|
||||
import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConverter;
|
||||
@@ -47,7 +48,6 @@ import org.springframework.hateoas.TemplateVariable.VariableType;
|
||||
import org.springframework.hateoas.TemplateVariables;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.core.AbstractEntityLinks;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -66,7 +66,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
private final @NonNull ResourceMappings mappings;
|
||||
private final @NonNull RepositoryRestConfiguration config;
|
||||
private final @NonNull PagingAndSortingTemplateVariables templateVariables;
|
||||
private final @NonNull PluginRegistry<BackendIdConverter, Class<?>> idConverters;
|
||||
private final @NonNull Java8PluginRegistry<BackendIdConverter, Class<?>> idConverters;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -135,7 +135,9 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
Assert.isInstanceOf(Serializable.class, id, "Id must be assignable to Serializable!");
|
||||
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
String mappedId = idConverters.getPluginFor(type, DefaultIdConverter.INSTANCE).toRequestId((Serializable) id, type);
|
||||
String mappedId = idConverters.getPluginFor(type)//
|
||||
.orElse(DefaultIdConverter.INSTANCE)//
|
||||
.toRequestId((Serializable) id, type);
|
||||
|
||||
Link link = linkFor(type).slash(mappedId).withRel(metadata.getItemResourceRel());
|
||||
return new Link(new UriTemplate(link.getHref(), getProjectionVariable(type)).toString(),
|
||||
|
||||
48
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AssociationLinksUnitTests.java
Normal file → Executable file
48
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AssociationLinksUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -26,11 +25,10 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.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.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
@@ -53,8 +51,8 @@ public class AssociationLinksUnitTests {
|
||||
Associations links;
|
||||
|
||||
ResourceMappings mappings;
|
||||
KeyValueMappingContext mappingContext;
|
||||
KeyValuePersistentEntity<?> entity;
|
||||
KeyValueMappingContext<?, ?> mappingContext;
|
||||
PersistentEntity<?, ?> entity;
|
||||
ResourceMetadata sampleResourceMetadata;
|
||||
|
||||
@Mock RepositoryRestConfiguration config;
|
||||
@@ -62,8 +60,8 @@ public class AssociationLinksUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mappingContext = new KeyValueMappingContext();
|
||||
this.entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
this.mappingContext = new KeyValueMappingContext<>();
|
||||
this.entity = mappingContext.getRequiredPersistentEntity(Sample.class);
|
||||
this.mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(mappingContext)));
|
||||
this.links = new Associations(mappings, config);
|
||||
}
|
||||
@@ -79,37 +77,33 @@ public class AssociationLinksUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAREST-262
|
||||
public void considersNullPropertyUnlinkable() {
|
||||
assertThat(links.isLinkableAssociation((PersistentProperty<?>) null), is(false));
|
||||
public void rejectsNullPropertyForIsLinkable() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
|
||||
links.isLinkableAssociation((PersistentProperty<?>) null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAREST-262
|
||||
public void consideredHiddenPropertyUnlinkable() {
|
||||
assertThat(links.isLinkableAssociation(entity.getPersistentProperty("hiddenProperty")), is(false));
|
||||
}
|
||||
|
||||
@Test // DATAREST-262
|
||||
public void considersUnexportedPropertyUnlinkable() {
|
||||
|
||||
KeyValuePersistentProperty property = entity.getPersistentProperty("unexportedProperty");
|
||||
assertThat(links.isLinkableAssociation(property), is(false));
|
||||
assertThat(links.isLinkableAssociation(entity.getRequiredPersistentProperty("hiddenProperty"))).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-262
|
||||
public void createsLinkToAssociationProperty() {
|
||||
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("property");
|
||||
List<Link> associationLinks = links.getLinksFor(property.getAssociation(), new Path("/base"));
|
||||
PersistentProperty<?> property = entity.getRequiredPersistentProperty("property");
|
||||
List<Link> associationLinks = links.getLinksFor(property.getRequiredAssociation(), new Path("/base"));
|
||||
|
||||
assertThat(associationLinks, hasSize(1));
|
||||
assertThat(associationLinks, hasItem(new Link("/base/property", "property")));
|
||||
assertThat(associationLinks).hasSize(1);
|
||||
assertThat(associationLinks).contains(new Link("/base/property", "property"));
|
||||
}
|
||||
|
||||
@Test // DATAREST-262
|
||||
public void doesNotCreateLinksForHiddenProperty() {
|
||||
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("hiddenProperty");
|
||||
assertThat(links.getLinksFor(property.getAssociation(), new Path("/sample")), hasSize(0));
|
||||
PersistentProperty<?> property = entity.getRequiredPersistentProperty("hiddenProperty");
|
||||
assertThat(links.getLinksFor(property.getRequiredAssociation(), new Path("/sample"))).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,12 +111,12 @@ public class AssociationLinksUnitTests {
|
||||
|
||||
doReturn(true).when(config).isLookupType(Property.class);
|
||||
|
||||
assertThat(links.isLookupType(entity.getPersistentProperty("hiddenProperty")), is(true));
|
||||
assertThat(links.isLookupType(entity.getRequiredPersistentProperty("hiddenProperty"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegatesResourceMetadataLookupToMappings() {
|
||||
assertThat(links.getMetadataFor(Property.class), is(mappings.getMetadataFor(Property.class)));
|
||||
assertThat(links.getMetadataFor(Property.class)).isEqualTo(mappings.getMetadataFor(Property.class));
|
||||
}
|
||||
|
||||
public static class Sample {
|
||||
|
||||
8
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AugmentingHandlerMappingUnitTests.java
Normal file → Executable file
8
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AugmentingHandlerMappingUnitTests.java
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -66,7 +64,7 @@ public class AugmentingHandlerMappingUnitTests {
|
||||
Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
|
||||
|
||||
for (RequestMappingInfo info : handlerMethods.keySet()) {
|
||||
assertThat(info.getPatternsCondition().getPatterns(), hasItem(Matchers.startsWith("/api")));
|
||||
assertThat(info.getPatternsCondition().getPatterns()).allMatch(it -> it.startsWith("/api"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java
Normal file → Executable file
13
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java
Normal file → Executable file
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -32,8 +33,8 @@ public class BaseUriUnitTests {
|
||||
@Test // DATAREST-276
|
||||
public void doesNotMatchNonOverlap() {
|
||||
|
||||
assertThat(new BaseUri(URI.create("foo")).getRepositoryLookupPath("/bar"), is(nullValue()));
|
||||
assertThat(new BaseUri(URI.create("http://localhost:8080/foo/")).getRepositoryLookupPath("/bar"), is(nullValue()));
|
||||
assertThat(new BaseUri(URI.create("foo")).getRepositoryLookupPath("/bar")).isNull();
|
||||
assertThat(new BaseUri(URI.create("http://localhost:8080/foo/")).getRepositoryLookupPath("/bar")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-276
|
||||
@@ -69,12 +70,12 @@ public class BaseUriUnitTests {
|
||||
|
||||
assertThat(uri.getRepositoryLookupPath("/foo"), isEmptyString());
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/"), isEmptyString());
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people"), is("/people"));
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people/"), is("/people"));
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people")).isEqualTo("/people");
|
||||
assertThat(uri.getRepositoryLookupPath("/foo/people/")).isEqualTo("/people");
|
||||
}
|
||||
|
||||
@Test // DATAREST-674, SPR-13455
|
||||
public void repositoryLookupPathHandlesDoubleSlashes() {
|
||||
assertThat(BaseUri.NONE.getRepositoryLookupPath("/books//1"), is("/books/1"));
|
||||
assertThat(BaseUri.NONE.getRepositoryLookupPath("/books//1")).isEqualTo("/books/1");
|
||||
}
|
||||
}
|
||||
|
||||
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/CustomAcceptHeaderHttpServletRequestUnitTests.java
Normal file → Executable file
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/CustomAcceptHeaderHttpServletRequestUnitTests.java
Normal file → Executable file
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -52,7 +53,7 @@ public class CustomAcceptHeaderHttpServletRequestUnitTests {
|
||||
|
||||
List<String> expected = Collections.list(servletRequest.getHeaders(HttpHeaders.ACCEPT));
|
||||
|
||||
assertThat(expected, hasSize(2));
|
||||
assertThat(expected, hasItems(MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_ATOM_XML_VALUE));
|
||||
assertThat(expected).hasSize(2);
|
||||
assertThat(expected).contains(MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_ATOM_XML_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/IncomingRequestUnitTests.java
Normal file → Executable file
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/IncomingRequestUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -44,8 +43,8 @@ public class IncomingRequestUnitTests {
|
||||
|
||||
IncomingRequest incomingRequest = new IncomingRequest(new ServletServerHttpRequest(request));
|
||||
|
||||
assertThat(incomingRequest.isJsonPatchRequest(), is(true));
|
||||
assertThat(incomingRequest.isJsonMergePatchRequest(), is(false));
|
||||
assertThat(incomingRequest.isJsonPatchRequest()).isTrue();
|
||||
assertThat(incomingRequest.isJsonMergePatchRequest()).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-498
|
||||
@@ -55,7 +54,7 @@ public class IncomingRequestUnitTests {
|
||||
|
||||
IncomingRequest incomingRequest = new IncomingRequest(new ServletServerHttpRequest(request));
|
||||
|
||||
assertThat(incomingRequest.isJsonPatchRequest(), is(false));
|
||||
assertThat(incomingRequest.isJsonMergePatchRequest(), is(true));
|
||||
assertThat(incomingRequest.isJsonPatchRequest()).isFalse();
|
||||
assertThat(incomingRequest.isJsonMergePatchRequest()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java
Normal file → Executable file
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -24,7 +23,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Resources;
|
||||
@@ -68,7 +67,7 @@ public class PersistentEntityResourceUnitTests {
|
||||
|
||||
PersistentEntityResource resource = PersistentEntityResource.build(payload, entity).build();
|
||||
|
||||
assertThat(resource.getEmbeddeds(), is(notNullValue()));
|
||||
assertThat(resource.getEmbeddeds(), is(emptyIterable()));
|
||||
assertThat(resource.getEmbeddeds()).isNotNull();
|
||||
assertThat(resource.getEmbeddeds()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
52
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryCorsConfigurationAccessorUnitTests.java
Normal file → Executable file
52
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryCorsConfigurationAccessorUnitTests.java
Normal file → Executable file
@@ -15,20 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
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.webmvc.RepositoryRestHandlerMapping.NoOpStringValueResolver;
|
||||
import org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.RepositoryCorsConfigurationAccessor;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
@@ -53,7 +53,8 @@ public class RepositoryCorsConfigurationAccessorUnitTests {
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
accessor = new RepositoryCorsConfigurationAccessor(mappings, NoOpStringValueResolver.INSTANCE, repositories);
|
||||
accessor = new RepositoryCorsConfigurationAccessor(mappings, NoOpStringValueResolver.INSTANCE,
|
||||
Optional.of(repositories));
|
||||
}
|
||||
|
||||
@Test // DATAREST-573
|
||||
@@ -61,13 +62,13 @@ public class RepositoryCorsConfigurationAccessorUnitTests {
|
||||
|
||||
CorsConfiguration configuration = accessor.createConfiguration(AnnotatedRepository.class);
|
||||
|
||||
assertThat(configuration, is(notNullValue()));
|
||||
assertThat(configuration.getAllowCredentials(), is(true));
|
||||
assertThat(configuration.getAllowedHeaders(), hasItem("*"));
|
||||
assertThat(configuration.getAllowedOrigins(), hasItem("*"));
|
||||
assertThat(configuration).isNotNull();
|
||||
assertThat(configuration.getAllowCredentials()).isTrue();
|
||||
assertThat(configuration.getAllowedHeaders()).contains("*");
|
||||
assertThat(configuration.getAllowedOrigins()).contains("*");
|
||||
assertThat(configuration.getAllowedMethods(),
|
||||
hasItems("OPTIONS", "HEAD", "GET", "PATCH", "POST", "PUT", "DELETE", "TRACE"));
|
||||
assertThat(configuration.getMaxAge(), is(1800L));
|
||||
assertThat(configuration.getMaxAge()).isEqualTo(1800L);
|
||||
}
|
||||
|
||||
@Test // DATAREST-573
|
||||
@@ -75,30 +76,25 @@ public class RepositoryCorsConfigurationAccessorUnitTests {
|
||||
|
||||
CorsConfiguration configuration = accessor.createConfiguration(FullyConfiguredCorsRepository.class);
|
||||
|
||||
assertThat(configuration, is(notNullValue()));
|
||||
assertThat(configuration.getAllowCredentials(), is(true));
|
||||
assertThat(configuration.getAllowedHeaders(), hasItem("Content-type"));
|
||||
assertThat(configuration.getExposedHeaders(), hasItem("Accept"));
|
||||
assertThat(configuration.getAllowedOrigins(), hasItem("http://far.far.away"));
|
||||
assertThat(configuration.getAllowedMethods(), hasItem("PATCH"));
|
||||
assertThat(configuration.getAllowedMethods(), not(hasItem("DELETE")));
|
||||
assertThat(configuration.getAllowCredentials(), is(true));
|
||||
assertThat(configuration.getMaxAge(), is(1234L));
|
||||
assertThat(configuration).isNotNull();
|
||||
assertThat(configuration.getAllowCredentials()).isTrue();
|
||||
assertThat(configuration.getAllowedHeaders()).contains("Content-type");
|
||||
assertThat(configuration.getExposedHeaders()).contains("Accept");
|
||||
assertThat(configuration.getAllowedOrigins()).contains("http://far.far.away");
|
||||
assertThat(configuration.getAllowedMethods()).contains("PATCH");
|
||||
assertThat(configuration.getAllowedMethods()).doesNotContain("DELETE");
|
||||
assertThat(configuration.getAllowCredentials()).isTrue();
|
||||
assertThat(configuration.getMaxAge()).isEqualTo(1234L);
|
||||
}
|
||||
|
||||
@Test // DATAREST-994
|
||||
public void returnsNullCorsConfigurationWithNullRepositories() {
|
||||
public void returnsNoCorsConfigurationWithNoRepositories() {
|
||||
|
||||
accessor = new RepositoryCorsConfigurationAccessor(mappings, NoOpStringValueResolver.INSTANCE, null);
|
||||
|
||||
ResourceMetadata resourceMetadata = mock(ResourceMetadata.class);
|
||||
when(resourceMetadata.getPath()).thenReturn(new Path("/people"));
|
||||
when(resourceMetadata.isExported()).thenReturn(true);
|
||||
accessor = new RepositoryCorsConfigurationAccessor(mappings, NoOpStringValueResolver.INSTANCE, Optional.empty());
|
||||
|
||||
when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true);
|
||||
when(mappings.iterator()).thenReturn(singletonList(resourceMetadata).iterator());
|
||||
|
||||
assertThat(accessor.findCorsConfiguration("/people"), is(nullValue()));
|
||||
assertThat(accessor.findCorsConfiguration("/people")).isEmpty();
|
||||
}
|
||||
|
||||
interface PlainRepository {}
|
||||
|
||||
13
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceControllerUnitTests.java
Normal file → Executable file
13
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceControllerUnitTests.java
Normal file → Executable file
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -23,12 +23,13 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
@@ -62,12 +63,12 @@ public class RepositoryPropertyReferenceControllerUnitTests {
|
||||
@Mock RepositoryInvoker invoker;
|
||||
@Mock ApplicationEventPublisher publisher;
|
||||
|
||||
KeyValueMappingContext mappingContext = new KeyValueMappingContext();
|
||||
KeyValueMappingContext<?, ?> mappingContext = new KeyValueMappingContext<>();
|
||||
|
||||
@Test // DATAREST-791
|
||||
public void usesRepositoryInvokerToLookupRelatedInstance() throws Exception {
|
||||
|
||||
KeyValuePersistentEntity<?> entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
KeyValuePersistentEntity<?, ?> entity = mappingContext.getRequiredPersistentEntity(Sample.class);
|
||||
|
||||
ResourceMappings mappings = new PersistentEntitiesResourceMappings(
|
||||
new PersistentEntities(Collections.singleton(mappingContext)));
|
||||
@@ -79,8 +80,8 @@ public class RepositoryPropertyReferenceControllerUnitTests {
|
||||
controller.setApplicationEventPublisher(publisher);
|
||||
|
||||
doReturn(invoker).when(invokerFactory).getInvokerFor(Reference.class);
|
||||
doReturn(new Sample()).when(invoker).invokeFindOne(4711);
|
||||
doReturn(new Reference()).when(invoker).invokeFindOne("some-id");
|
||||
doReturn(Optional.of(new Sample())).when(invoker).invokeFindOne(4711);
|
||||
doReturn(Optional.of(new Reference())).when(invoker).invokeFindOne("some-id");
|
||||
doReturn(new Sample()).when(invoker).invokeSave(any(Object.class));
|
||||
|
||||
RootResourceInformation information = new RootResourceInformation(metadata, entity, invoker);
|
||||
|
||||
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandlerUnitTests.java
Normal file → Executable file
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandlerUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
@@ -63,7 +62,7 @@ public class RepositoryRestExceptionHandlerUnitTests {
|
||||
ResponseEntity<ExceptionMessage> result = HANDLER
|
||||
.handleNotReadable(new HttpMessageNotReadableException("Message!"));
|
||||
|
||||
assertThat(result.getStatusCode(), is(HttpStatus.BAD_REQUEST));
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test // DATAREST-507
|
||||
@@ -71,7 +70,7 @@ public class RepositoryRestExceptionHandlerUnitTests {
|
||||
|
||||
ResponseEntity<ExceptionMessage> result = HANDLER.handleConflict(new DataIntegrityViolationException("Message!"));
|
||||
|
||||
assertThat(result.getStatusCode(), is(HttpStatus.CONFLICT));
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
@Test // DATAREST-706
|
||||
@@ -81,7 +80,7 @@ public class RepositoryRestExceptionHandlerUnitTests {
|
||||
|
||||
ResponseEntity<ExceptionMessage> result = HANDLER.handleMiscFailures(new Exception(message));
|
||||
|
||||
assertThat(result.getBody(), is(notNullValue()));
|
||||
assertThat(result.getBody().getMessage(), is(message));
|
||||
assertThat(result.getBody()).isNotNull();
|
||||
assertThat(result.getBody().getMessage()).isEqualTo(message);
|
||||
}
|
||||
}
|
||||
|
||||
37
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java
Normal file → Executable file
37
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -25,7 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.config.EnumTranslationConfiguration;
|
||||
@@ -46,7 +45,7 @@ import org.springframework.web.method.HandlerMethod;
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
static final AnnotationConfigWebApplicationContext CONTEXT = new AnnotationConfigWebApplicationContext();
|
||||
@@ -95,7 +94,7 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
public void returnsNullForUriNotMapped() throws Exception {
|
||||
|
||||
handlerMapping.afterPropertiesSet();
|
||||
assertThat(handlerMapping.lookupHandlerMethod("/foo", mockRequest), is(nullValue()));
|
||||
assertThat(handlerMapping.lookupHandlerMethod("/foo", mockRequest)).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-111
|
||||
@@ -107,8 +106,8 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
handlerMapping.afterPropertiesSet();
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/people", mockRequest);
|
||||
|
||||
assertThat(method, is(notNullValue()));
|
||||
assertThat(method.getMethod(), is(listEntitiesMethod));
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
|
||||
}
|
||||
|
||||
@Test // DATAREST-292
|
||||
@@ -122,14 +121,13 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base/people", mockRequest);
|
||||
|
||||
assertThat(method, is(notNullValue()));
|
||||
assertThat(method.getMethod(), is(listEntitiesMethod));
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
|
||||
}
|
||||
|
||||
@Test // DATAREST-292
|
||||
public void returnsRootHandlerMethodWithBaseUriConfigured() throws Exception {
|
||||
|
||||
when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true);
|
||||
mockRequest = new MockHttpServletRequest("GET", "/base");
|
||||
|
||||
configuration.setBasePath("/base");
|
||||
@@ -137,8 +135,8 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base", mockRequest);
|
||||
|
||||
assertThat(method, is(notNullValue()));
|
||||
assertThat(method.getMethod(), is(rootHandlerMethod));
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(method.getMethod()).isEqualTo(rootHandlerMethod);
|
||||
}
|
||||
|
||||
@Test // DATAREST-276
|
||||
@@ -152,8 +150,8 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base/people/", mockRequest);
|
||||
|
||||
assertThat(method, is(notNullValue()));
|
||||
assertThat(method.getMethod(), is(listEntitiesMethod));
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
|
||||
}
|
||||
|
||||
@Test // DATAREST-276
|
||||
@@ -168,14 +166,13 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base/people", mockRequest);
|
||||
|
||||
assertThat(method, is(notNullValue()));
|
||||
assertThat(method.getMethod(), is(listEntitiesMethod));
|
||||
assertThat(method).isNotNull();
|
||||
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
|
||||
}
|
||||
|
||||
@Test // DATAREST-276
|
||||
public void refrainsFromMappingIfTheRequestDoesNotPointIntoAbsolutelyDefinedUriSpace() throws Exception {
|
||||
|
||||
when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true);
|
||||
mockRequest = new MockHttpServletRequest("GET", "/servlet-path");
|
||||
mockRequest.setServletPath("/servlet-path");
|
||||
|
||||
@@ -183,7 +180,7 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/servlet-path", mockRequest);
|
||||
|
||||
assertThat(method, is(nullValue()));
|
||||
assertThat(method).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-276
|
||||
@@ -200,7 +197,7 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
HandlerMethod method = handlerMapping.lookupHandlerMethod("/people", mockRequest);
|
||||
|
||||
assertThat(method, is(nullValue()));
|
||||
assertThat(method).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-609
|
||||
@@ -210,7 +207,7 @@ public class RepositoryRestHandlerMappingUnitTests {
|
||||
|
||||
mockRequest = new MockHttpServletRequest("GET", "/people{?projection}");
|
||||
|
||||
assertThat(handlerMapping.getHandler(mockRequest), is(nullValue()));
|
||||
assertThat(handlerMapping.getHandler(mockRequest)).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-994
|
||||
|
||||
5
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositorySearchesResourceUnitTests.java
Normal file → Executable file
5
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositorySearchesResourceUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -35,6 +34,6 @@ public class RepositorySearchesResourceUnitTests {
|
||||
|
||||
@Test // DATAREST-515
|
||||
public void returnsConfiguredDomainType() {
|
||||
assertThat(new RepositorySearchesResource(String.class).getDomainType(), is(typeCompatibleWith(String.class)));
|
||||
assertThat(new RepositorySearchesResource(String.class).getDomainType()).isAssignableFrom(String.class);
|
||||
}
|
||||
}
|
||||
|
||||
29
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/ResourceStatusUnitTests.java
Normal file → Executable file
29
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/ResourceStatusUnitTests.java
Normal file → Executable file
@@ -15,23 +15,22 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.rest.core.util.Supplier;
|
||||
import org.springframework.data.rest.webmvc.ResourceStatus.StatusAndHeaders;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -45,7 +44,7 @@ import org.springframework.http.HttpStatus;
|
||||
public class ResourceStatusUnitTests {
|
||||
|
||||
ResourceStatus status;
|
||||
KeyValuePersistentEntity<?> entity;
|
||||
KeyValuePersistentEntity<?, ?> entity;
|
||||
|
||||
@Mock HttpHeadersPreparer preparer;
|
||||
@Mock Supplier<PersistentEntityResource> supplier;
|
||||
@@ -55,10 +54,10 @@ public class ResourceStatusUnitTests {
|
||||
|
||||
this.status = ResourceStatus.of(preparer);
|
||||
|
||||
KeyValueMappingContext context = new KeyValueMappingContext();
|
||||
this.entity = context.getPersistentEntity(Sample.class);
|
||||
KeyValueMappingContext<?, ?> context = new KeyValueMappingContext<>();
|
||||
this.entity = context.getRequiredPersistentEntity(Sample.class);
|
||||
|
||||
doReturn(new HttpHeaders()).when(preparer).prepareHeaders(eq(entity), Matchers.any());
|
||||
doReturn(new HttpHeaders()).when(preparer).prepareHeaders(eq(entity), any());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAREST-835
|
||||
@@ -83,22 +82,22 @@ public class ResourceStatusUnitTests {
|
||||
@Test // DATAREST-835
|
||||
public void returnsNotModifiedIfEntityIsStillConsideredValid() {
|
||||
|
||||
doReturn(true).when(preparer).isObjectStillValid(Matchers.any(), Matchers.any(HttpHeaders.class));
|
||||
doReturn(true).when(preparer).isObjectStillValid(any(), any(HttpHeaders.class));
|
||||
|
||||
assertNotModified(status.getStatusAndHeaders(new HttpHeaders(), new Sample(0), entity));
|
||||
}
|
||||
|
||||
private void assertModified(StatusAndHeaders statusAndHeaders) {
|
||||
|
||||
assertThat(statusAndHeaders.isModified(), is(true));
|
||||
assertThat(statusAndHeaders.toResponseEntity(supplier).getStatusCode(), is(HttpStatus.OK));
|
||||
assertThat(statusAndHeaders.isModified()).isTrue();
|
||||
assertThat(statusAndHeaders.toResponseEntity(supplier).getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
verify(supplier).get();
|
||||
}
|
||||
|
||||
private void assertNotModified(StatusAndHeaders statusAndHeaders) {
|
||||
|
||||
assertThat(statusAndHeaders.isModified(), is(false));
|
||||
assertThat(statusAndHeaders.toResponseEntity(supplier).getStatusCode(), is(HttpStatus.NOT_MODIFIED));
|
||||
assertThat(statusAndHeaders.isModified()).isFalse();
|
||||
assertThat(statusAndHeaders.toResponseEntity(supplier).getStatusCode()).isEqualTo(HttpStatus.NOT_MODIFIED);
|
||||
}
|
||||
|
||||
@Value
|
||||
|
||||
2
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RootResourceInformationUnitTests.java
Normal file → Executable file
2
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RootResourceInformationUnitTests.java
Normal file → Executable file
@@ -25,7 +25,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -63,19 +62,19 @@ public class ArgumentResolverPagingAndSortingTemplateVariablesUnitTests {
|
||||
PagingAndSortingTemplateVariables variables = new ArgumentResolverPagingAndSortingTemplateVariables(
|
||||
pageableResolver, sortResolver);
|
||||
|
||||
assertThat(variables.supportsParameter(getParameterMock(Pageable.class)), is(true));
|
||||
assertThat(variables.supportsParameter(getParameterMock(Sort.class)), is(true));
|
||||
assertThat(variables.supportsParameter(getParameterMock(Object.class)), is(false));
|
||||
assertThat(variables.supportsParameter(getParameterMock(Pageable.class))).isTrue();
|
||||
assertThat(variables.supportsParameter(getParameterMock(Sort.class))).isTrue();
|
||||
assertThat(variables.supportsParameter(getParameterMock(Object.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-467
|
||||
public void forwardsEnhanceRequestForPageable() {
|
||||
assertForwardsEnhanceFor(new PageRequest(0, 10), pageableResolver, sortResolver);
|
||||
assertForwardsEnhanceFor(PageRequest.of(0, 10), pageableResolver, sortResolver);
|
||||
}
|
||||
|
||||
@Test // DATAREST-467
|
||||
public void forwardsEnhanceRequestForSort() {
|
||||
assertForwardsEnhanceFor(new Sort("property"), sortResolver, pageableResolver);
|
||||
assertForwardsEnhanceFor(Sort.by("property"), sortResolver, pageableResolver);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@@ -97,6 +96,6 @@ public class ArgumentResolverPagingAndSortingTemplateVariablesUnitTests {
|
||||
|
||||
verify(expected, times(1)).enhance(builder, null, value);
|
||||
verify(unexpected, times(0)).enhance(Mockito.any(UriComponentsBuilder.class), Mockito.any(MethodParameter.class),
|
||||
anyObject());
|
||||
any());
|
||||
}
|
||||
}
|
||||
|
||||
47
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java
Normal file → Executable file
47
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvConfigurationIntegrationTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.config;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@@ -85,8 +84,8 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
@Test // DATAREST-210
|
||||
public void assertEnableHypermediaSupportWorkingCorrectly() {
|
||||
|
||||
assertThat(context.getBean("entityLinksPluginRegistry"), is(notNullValue()));
|
||||
assertThat(context.getBean(LinkDiscoverers.class), is(notNullValue()));
|
||||
assertThat(context.getBean("entityLinksPluginRegistry")).isNotNull();
|
||||
assertThat(context.getBean(LinkDiscoverers.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,15 +106,15 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
.getBean(HateoasPageableHandlerMethodArgumentResolver.class);
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
|
||||
resolver.enhance(builder, null, new PageRequest(0, 9000, Direction.ASC, "firstname"));
|
||||
resolver.enhance(builder, null, PageRequest.of(0, 9000, Direction.ASC, "firstname"));
|
||||
|
||||
MultiValueMap<String, String> params = builder.build().getQueryParams();
|
||||
|
||||
assertThat(params.containsKey("myPage"), is(true));
|
||||
assertThat(params.containsKey("mySort"), is(true));
|
||||
assertThat(params.containsKey("myPage")).isTrue();
|
||||
assertThat(params.containsKey("mySort")).isTrue();
|
||||
|
||||
assertThat(params.get("mySize"), hasSize(1));
|
||||
assertThat(params.get("mySize").get(0), is("7000"));
|
||||
assertThat(params.get("mySize")).hasSize(1);
|
||||
assertThat(params.get("mySize").get(0)).isEqualTo("7000");
|
||||
}
|
||||
|
||||
@Test // DATAREST-336
|
||||
@@ -131,8 +130,8 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
Object result = JsonPath.read(mapper.writeValueAsString(sample), "$.date");
|
||||
assertThat(result, is(instanceOf(String.class)));
|
||||
assertThat(result, is((Object) formatter.print(sample.date, Locale.US)));
|
||||
assertThat(result).isInstanceOf(String.class);
|
||||
assertThat(result).isEqualTo(formatter.print(sample.date, Locale.US));
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchBeanDefinitionException.class) // DATAREST-362
|
||||
@@ -146,10 +145,10 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
Collection<MappingJackson2HttpMessageConverter> converters = context
|
||||
.getBeansOfType(MappingJackson2HttpMessageConverter.class).values();
|
||||
|
||||
for (HttpMessageConverter<?> converter : converters) {
|
||||
assertThat(converter, is(anyOf(instanceOf(TypeConstrainedMappingJackson2HttpMessageConverter.class),
|
||||
instanceOf(AlpsJsonHttpMessageConverter.class))));
|
||||
}
|
||||
converters.forEach(converter -> {
|
||||
assertThat(converter).isInstanceOfAny(TypeConstrainedMappingJackson2HttpMessageConverter.class,
|
||||
AlpsJsonHttpMessageConverter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAREST-424
|
||||
@@ -158,8 +157,8 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
CollectingComponent component = context.getBean(CollectingComponent.class);
|
||||
List<HttpMessageConverter<?>> converters = component.converters;
|
||||
|
||||
assertThat(converters.get(0).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON));
|
||||
assertThat(converters.get(1).getSupportedMediaTypes(), hasItem(RestMediaTypes.SCHEMA_JSON));
|
||||
assertThat(converters.get(0).getSupportedMediaTypes()).contains(MediaTypes.HAL_JSON);
|
||||
assertThat(converters.get(1).getSupportedMediaTypes()).contains(RestMediaTypes.SCHEMA_JSON);
|
||||
}
|
||||
|
||||
@Test // DATAREST-424
|
||||
@@ -171,8 +170,8 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = component.converters;
|
||||
|
||||
assertThat(converters.get(0).getSupportedMediaTypes(), hasItem(RestMediaTypes.SCHEMA_JSON));
|
||||
assertThat(converters.get(1).getSupportedMediaTypes(), hasItem(MediaTypes.HAL_JSON));
|
||||
assertThat(converters.get(0).getSupportedMediaTypes()).contains(RestMediaTypes.SCHEMA_JSON);
|
||||
assertThat(converters.get(1).getSupportedMediaTypes()).contains(MediaTypes.HAL_JSON);
|
||||
}
|
||||
|
||||
@Test // DATAREST-431, DATACMNS-626
|
||||
@@ -180,10 +179,10 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
|
||||
ConversionService service = context.getBean("defaultConversionService", ConversionService.class);
|
||||
|
||||
assertThat(service.canConvert(String.class, Point.class), is(true));
|
||||
assertThat(service.canConvert(Point.class, String.class), is(true));
|
||||
assertThat(service.canConvert(String.class, Distance.class), is(true));
|
||||
assertThat(service.canConvert(Distance.class, String.class), is(true));
|
||||
assertThat(service.canConvert(String.class, Point.class)).isTrue();
|
||||
assertThat(service.canConvert(Point.class, String.class)).isTrue();
|
||||
assertThat(service.canConvert(String.class, Distance.class)).isTrue();
|
||||
assertThat(service.canConvert(Distance.class, String.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAREST-686
|
||||
@@ -193,7 +192,7 @@ public class RepositoryRestMvConfigurationIntegrationTests {
|
||||
MessageSourceAccessor.class);
|
||||
Object messageSource = ReflectionTestUtils.getField(accessor, "messageSource");
|
||||
|
||||
assertThat((String) ReflectionTestUtils.getField(messageSource, "defaultEncoding"), is("UTF-8"));
|
||||
assertThat((String) ReflectionTestUtils.getField(messageSource, "defaultEncoding")).isEqualTo("UTF-8");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
113
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java
Normal file → Executable file
113
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/DomainObjectReaderUnitTests.java
Normal file → Executable file
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -42,7 +43,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
@@ -82,7 +83,7 @@ public class DomainObjectReaderUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
KeyValueMappingContext mappingContext = new KeyValueMappingContext();
|
||||
KeyValueMappingContext<?, ?> mappingContext = new KeyValueMappingContext<>();
|
||||
mappingContext.getPersistentEntity(SampleUser.class);
|
||||
mappingContext.getPersistentEntity(Person.class);
|
||||
mappingContext.getPersistentEntity(TypeWithGenericMap.class);
|
||||
@@ -112,8 +113,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
SampleUser result = reader.readPut((ObjectNode) node, user, new ObjectMapper());
|
||||
|
||||
assertThat(result.name, is(nullValue()));
|
||||
assertThat(result.password, is("password"));
|
||||
assertThat(result.name).isNull();
|
||||
assertThat(result.password).isEqualTo("password");
|
||||
}
|
||||
|
||||
@Test // DATAREST-556
|
||||
@@ -126,8 +127,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Person result = reader.readPut((ObjectNode) node, new Person("Dave", "Matthews"), mapper);
|
||||
|
||||
assertThat(result.firstName, is("Carter"));
|
||||
assertThat(result.lastName, is("Beauford"));
|
||||
assertThat(result.firstName).isEqualTo("Carter");
|
||||
assertThat(result.lastName).isEqualTo("Beauford");
|
||||
}
|
||||
|
||||
@Test // DATAREST-605
|
||||
@@ -142,8 +143,8 @@ public class DomainObjectReaderUnitTests {
|
||||
SampleUser result = reader.readPut((ObjectNode) node, user, new ObjectMapper());
|
||||
|
||||
// Assert that the nested Map values also consider ignored properties
|
||||
assertThat(result.relatedUsers.get("parent").password, is("password"));
|
||||
assertThat(result.relatedUsers.get("parent").name, is("Oliver"));
|
||||
assertThat(result.relatedUsers.get("parent").password).isEqualTo("password");
|
||||
assertThat(result.relatedUsers.get("parent").name).isEqualTo("Oliver");
|
||||
}
|
||||
|
||||
@Test // DATAREST-701
|
||||
@@ -159,11 +160,11 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
TypeWithGenericMap result = reader.readPut((ObjectNode) node, target, mapper);
|
||||
|
||||
assertThat(result.map.get("a"), is((Object) "1"));
|
||||
assertThat(result.map.get("a")).isEqualTo((Object) "1");
|
||||
|
||||
Object object = result.map.get("b");
|
||||
assertThat(object, is(instanceOf(Map.class)));
|
||||
assertThat(((Map<Object, Object>) object).get("c"), is((Object) "2"));
|
||||
assertThat(object).isInstanceOf(Map.class);
|
||||
assertThat(((Map<Object, Object>) object).get("c")).isEqualTo((Object) "2");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAREST-701
|
||||
@@ -188,10 +189,10 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
VersionedType result = reader.readPut(node, type, mapper);
|
||||
|
||||
assertThat(result.lastname, is("Matthews"));
|
||||
assertThat(result.firstname, is(nullValue()));
|
||||
assertThat(result.id, is(1L));
|
||||
assertThat(result.version, is(1L));
|
||||
assertThat(result.lastname).isEqualTo("Matthews");
|
||||
assertThat(result.firstname).isNull();
|
||||
assertThat(result.id).isEqualTo(1L);
|
||||
assertThat(result.version).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@Test // DATAREST-873
|
||||
@@ -205,7 +206,7 @@ public class DomainObjectReaderUnitTests {
|
||||
SampleWithCreatedDate sample = new SampleWithCreatedDate();
|
||||
sample.createdDate = reference;
|
||||
|
||||
assertThat(reader.readPut(node, sample, mapper).createdDate, is(reference));
|
||||
assertThat(reader.readPut(node, sample, mapper).createdDate).isEqualTo(reference);
|
||||
}
|
||||
|
||||
@Test // DATAREST-931
|
||||
@@ -222,7 +223,7 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
User result = reader.read(source, user, new ObjectMapper());
|
||||
|
||||
assertThat(result.phones.get(0).creationDate, is(notNullValue()));
|
||||
assertThat(result.phones.get(0).creationDate).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-919
|
||||
@@ -249,18 +250,18 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
TypeWithGenericMap result = reader.readPut(payload, map, mapper);
|
||||
|
||||
assertThat(result.map.get("sub1"), is((Object) "ok"));
|
||||
assertThat(result.map.get("sub1")).isEqualTo((Object) "ok");
|
||||
|
||||
List<String> sub2 = as(result.map.get("sub2"), List.class);
|
||||
assertThat(sub2.get(0), is("ok1"));
|
||||
assertThat(sub2.get(1), is("ok2"));
|
||||
assertThat(sub2.get(0)).isEqualTo("ok1");
|
||||
assertThat(sub2.get(1)).isEqualTo("ok2");
|
||||
|
||||
List<Map<String, String>> sub3 = as(result.map.get("sub3"), List.class);
|
||||
assertThat(sub3.get(0).get("childOk1"), is("ok"));
|
||||
assertThat(sub3.get(0).get("childOk1")).isEqualTo("ok");
|
||||
|
||||
Map<Object, String> sub4 = as(result.map.get("sub4"), Map.class);
|
||||
assertThat(sub4.get("c1"), is("v1"));
|
||||
assertThat(sub4.get("c2"), is("new"));
|
||||
assertThat(sub4.get("c1")).isEqualTo("v1");
|
||||
assertThat(sub4.get("c2")).isEqualTo("new");
|
||||
}
|
||||
|
||||
@Test // DATAREST-938
|
||||
@@ -279,11 +280,11 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Outer result = reader.doMerge((ObjectNode) node, outer, new ObjectMapper());
|
||||
|
||||
assertThat(result, is(sameInstance(outer)));
|
||||
assertThat(result.prop, is("else"));
|
||||
assertThat(result.inner.prop, is("something"));
|
||||
assertThat(result.inner.name, is("new inner name"));
|
||||
assertThat(result.inner, is(sameInstance(inner)));
|
||||
assertThat(result).isSameAs(outer);
|
||||
assertThat(result.prop).isEqualTo("else");
|
||||
assertThat(result.inner.prop).isEqualTo("something");
|
||||
assertThat(result.inner.name).isEqualTo("new inner name");
|
||||
assertThat(result.inner).isSameAs(inner);
|
||||
}
|
||||
|
||||
@Test // DATAREST-937
|
||||
@@ -297,8 +298,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
SampleWithTransient result = reader.readPut((ObjectNode) node, sample, new ObjectMapper());
|
||||
|
||||
assertThat(result.name, is("new name"));
|
||||
assertThat(result.temporary, is("new temp"));
|
||||
assertThat(result.name).isEqualTo("new name");
|
||||
assertThat(result.temporary).isEqualTo("new temp");
|
||||
}
|
||||
|
||||
@Test // DATAREST-953
|
||||
@@ -315,7 +316,7 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items.get(0).some, is("value"));
|
||||
assertThat(result.inner.items.get(0).some).isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test // DATAREST-956
|
||||
@@ -333,10 +334,10 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items.size(), is(3));
|
||||
assertThat(result.inner.items.get(0).some, is("value1"));
|
||||
assertThat(result.inner.items.get(1).some, is("value2"));
|
||||
assertThat(result.inner.items.get(2).some, is("value3"));
|
||||
assertThat(result.inner.items).hasSize(3);
|
||||
assertThat(result.inner.items.get(0).some).isEqualTo("value1");
|
||||
assertThat(result.inner.items.get(1).some).isEqualTo("value2");
|
||||
assertThat(result.inner.items.get(2).some).isEqualTo("value3");
|
||||
}
|
||||
|
||||
@Test // DATAREST-956
|
||||
@@ -355,8 +356,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items.size(), is(1));
|
||||
assertThat(result.inner.items.get(0).some, is("value"));
|
||||
assertThat(result.inner.items).hasSize(1);
|
||||
assertThat(result.inner.items.get(0).some).isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test // DATAREST-959
|
||||
@@ -370,8 +371,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items.size(), is(1));
|
||||
assertThat(result.inner.items.get(0).some, is("value"));
|
||||
assertThat(result.inner.items).hasSize(1);
|
||||
assertThat(result.inner.items.get(0).some).isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test // DATAREST-959
|
||||
@@ -386,14 +387,14 @@ public class DomainObjectReaderUnitTests {
|
||||
.readTree("{ \"inner\" : { \"object\" : [ { \"some\" : \"value\" }, { \"some\" : \"otherValue\" } ] } }");
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
assertThat(result.inner.object, is(instanceOf(Collection.class)));
|
||||
assertThat(result.inner.object).isInstanceOf(Collection.class);
|
||||
|
||||
Collection<?> collection = (Collection<?>) result.inner.object;
|
||||
assertThat(collection.size(), is(2));
|
||||
assertThat(collection).hasSize(2);
|
||||
|
||||
Iterator<Map<String, Object>> iterator = (Iterator<Map<String, Object>>) collection.iterator();
|
||||
assertThat(iterator.next().get("some"), is((Object) "value"));
|
||||
assertThat(iterator.next().get("some"), is((Object) "otherValue"));
|
||||
assertThat(iterator.next().get("some")).isEqualTo((Object) "value");
|
||||
assertThat(iterator.next().get("some")).isEqualTo((Object) "otherValue");
|
||||
}
|
||||
|
||||
@Test // DATAREST-965
|
||||
@@ -411,8 +412,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items, is(nullValue()));
|
||||
assertThat((String) result.inner.object, is("value"));
|
||||
assertThat(result.inner.items).isNull();
|
||||
assertThat((String) result.inner.object).isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test // DATAREST-965
|
||||
@@ -428,9 +429,9 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Parent result = reader.readPut((ObjectNode) node, source, new ObjectMapper());
|
||||
|
||||
assertThat(result.inner.items.size(), is(1));
|
||||
assertThat(result.inner.items.get(0).some, is("value"));
|
||||
assertThat(result.inner.object, is(nullValue()));
|
||||
assertThat(result.inner.items).hasSize(1);
|
||||
assertThat(result.inner.items.get(0).some).isEqualTo("value");
|
||||
assertThat(result.inner.object).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-986
|
||||
@@ -442,8 +443,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
Product result = reader.readPut((ObjectNode) node, new Product(), mapper);
|
||||
|
||||
assertThat(result.map.get(Locale.ENGLISH), is(new LocalizedValue("eventual")));
|
||||
assertThat(result.map.get(Locale.GERMAN), is(new LocalizedValue("schlussendlich")));
|
||||
assertThat(result.map.get(Locale.ENGLISH)).isEqualTo(new LocalizedValue("eventual"));
|
||||
assertThat(result.map.get(Locale.GERMAN)).isEqualTo(new LocalizedValue("schlussendlich"));
|
||||
}
|
||||
|
||||
@Test // DATAREST-987
|
||||
@@ -478,8 +479,8 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
SampleWithReference result = reader.mergeForPut(source, target, new ObjectMapper());
|
||||
|
||||
assertThat(result.nested, is(source.nested));
|
||||
assertThat(result.nested == originalCollection, is(false));
|
||||
assertThat(result.nested).isEqualTo(source.nested);
|
||||
assertThat(result.nested == originalCollection).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-944
|
||||
@@ -492,14 +493,14 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
SampleWithReference result = reader.mergeForPut(source, target, new ObjectMapper());
|
||||
|
||||
assertThat(result.nested, is(source.nested));
|
||||
assertThat(result.nested == originalCollection, is(true));
|
||||
assertThat(result.nested).isEqualTo(source.nested);
|
||||
assertThat(result.nested).isSameAs(originalCollection);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T as(Object source, Class<T> type) {
|
||||
|
||||
assertThat(source, is(instanceOf(type)));
|
||||
assertThat(source).isInstanceOf(type);
|
||||
return (T) source;
|
||||
}
|
||||
|
||||
|
||||
43
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/EnumTranslatorUnitTests.java
Normal file → Executable file
43
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/EnumTranslatorUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -54,17 +53,17 @@ public class EnumTranslatorUnitTests {
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void parsesNullForNullSource() {
|
||||
assertThat(configuration.fromText(MyEnum.class, null), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, null)).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void parsesNullForEmptySource() {
|
||||
assertThat(configuration.fromText(MyEnum.class, null), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, null)).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void parsesNullForUnknownValue() {
|
||||
assertThat(configuration.fromText(MyEnum.class, "Foobar"), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Foobar")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
@@ -72,13 +71,13 @@ public class EnumTranslatorUnitTests {
|
||||
|
||||
configuration.setEnableDefaultTranslation(false);
|
||||
|
||||
assertThat(configuration.asText(MyEnum.SECOND_VALUE), is(MyEnum.SECOND_VALUE.name()));
|
||||
assertThat(configuration.asText(MyEnum.SECOND_VALUE)).isEqualTo(MyEnum.SECOND_VALUE.name());
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void returnsDefaultTranslationByDefault() {
|
||||
|
||||
assertThat(configuration.asText(MyEnum.SECOND_VALUE), is("Second value"));
|
||||
assertThat(configuration.asText(MyEnum.SECOND_VALUE)).isEqualTo("Second value");
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
@@ -86,14 +85,14 @@ public class EnumTranslatorUnitTests {
|
||||
|
||||
configuration.setEnableDefaultTranslation(false);
|
||||
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE"), is(MyEnum.FIRST_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE")).isEqualTo(MyEnum.FIRST_VALUE);
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void parsesStandardTranslationAndEnumNameByDefault() {
|
||||
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE"), is(MyEnum.FIRST_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value"), is(MyEnum.SECOND_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE")).isEqualTo(MyEnum.FIRST_VALUE);
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value")).isEqualTo(MyEnum.SECOND_VALUE);
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
@@ -104,22 +103,22 @@ public class EnumTranslatorUnitTests {
|
||||
messageSource.addMessage(MyEnum.class.getName().concat(".").concat(MyEnum.FIRST_VALUE.name()), Locale.US,
|
||||
"Translated");
|
||||
|
||||
assertThat(configuration.asText(MyEnum.FIRST_VALUE), is("Translated"));
|
||||
assertThat(configuration.asText(MyEnum.FIRST_VALUE)).isEqualTo("Translated");
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
public void parsesEnumNameByDefaultEvenIfMessageDefined() {
|
||||
|
||||
// Parses resolved message and enum name
|
||||
assertThat(configuration.fromText(MyEnum.class, "Translated"), is(MyEnum.FIRST_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE"), is(MyEnum.FIRST_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Translated")).isEqualTo(MyEnum.FIRST_VALUE);
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE")).isEqualTo(MyEnum.FIRST_VALUE);
|
||||
|
||||
// Does not parse default translation as explicit translation is available
|
||||
assertThat(configuration.fromText(MyEnum.class, "First value"), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, "First value")).isNull();
|
||||
|
||||
// Parses default translation as no explicit translation is available
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value"), is(MyEnum.SECOND_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE"), is(MyEnum.SECOND_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value")).isEqualTo(MyEnum.SECOND_VALUE);
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE")).isEqualTo(MyEnum.SECOND_VALUE);
|
||||
}
|
||||
|
||||
@Test // DATAREST-654
|
||||
@@ -128,8 +127,8 @@ public class EnumTranslatorUnitTests {
|
||||
configuration.setEnableDefaultTranslation(false);
|
||||
|
||||
// Parses default translation as no explicit translation is available
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value"), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE"), is(MyEnum.SECOND_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value")).isNull();
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE")).isEqualTo(MyEnum.SECOND_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -138,12 +137,12 @@ public class EnumTranslatorUnitTests {
|
||||
configuration.setParseEnumNameAsFallback(false);
|
||||
|
||||
// Parses resolved message and enum name
|
||||
assertThat(configuration.fromText(MyEnum.class, "Translated"), is(MyEnum.FIRST_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE"), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Translated")).isEqualTo(MyEnum.FIRST_VALUE);
|
||||
assertThat(configuration.fromText(MyEnum.class, "FIRST_VALUE")).isNull();
|
||||
|
||||
// Parses default translation as no explicit translation is available
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value"), is(MyEnum.SECOND_VALUE));
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE"), is(nullValue()));
|
||||
assertThat(configuration.fromText(MyEnum.class, "Second value")).isEqualTo(MyEnum.SECOND_VALUE);
|
||||
assertThat(configuration.fromText(MyEnum.class, "SECOND_VALUE")).isNull();
|
||||
}
|
||||
|
||||
static enum MyEnum {
|
||||
|
||||
21
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JacksonMetadataUnitTests.java
Normal file → Executable file
21
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JacksonMetadataUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -51,7 +50,7 @@ public class JacksonMetadataUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.context = new KeyValueMappingContext();
|
||||
this.context = new KeyValueMappingContext<>();
|
||||
|
||||
this.mapper = new ObjectMapper();
|
||||
this.mapper.disable(MapperFeature.INFER_PROPERTY_MUTATORS);
|
||||
@@ -62,11 +61,11 @@ public class JacksonMetadataUnitTests {
|
||||
|
||||
JacksonMetadata metadata = new JacksonMetadata(mapper, User.class);
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(User.class);
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("username");
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(User.class);
|
||||
PersistentProperty<?> property = entity.getRequiredPersistentProperty("username");
|
||||
|
||||
assertThat(metadata.isExported(property), is(true));
|
||||
assertThat(metadata.isReadOnly(property), is(true));
|
||||
assertThat(metadata.isExported(property)).isTrue();
|
||||
assertThat(metadata.isReadOnly(property)).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAREST-644
|
||||
@@ -74,10 +73,10 @@ public class JacksonMetadataUnitTests {
|
||||
|
||||
JacksonMetadata metadata = new JacksonMetadata(mapper, Value.class);
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(Value.class);
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("value");
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(Value.class);
|
||||
PersistentProperty<?> property = entity.getRequiredPersistentProperty("value");
|
||||
|
||||
assertThat(metadata.isReadOnly(property), is(false));
|
||||
assertThat(metadata.isReadOnly(property)).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-644
|
||||
@@ -86,7 +85,7 @@ public class JacksonMetadataUnitTests {
|
||||
JsonSerializer<?> serializer = new JacksonMetadata(new ObjectMapper(), SomeBean.class)
|
||||
.getTypeSerializer(SomeBean.class);
|
||||
|
||||
assertThat(serializer, is(instanceOf(SomeBeanSerializer.class)));
|
||||
assertThat(serializer).isInstanceOf(SomeBeanSerializer.class);
|
||||
}
|
||||
|
||||
static class User {
|
||||
|
||||
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JacksonSerializersUnitTests.java
Normal file → Executable file
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JacksonSerializersUnitTests.java
Normal file → Executable file
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -53,7 +54,7 @@ public class JacksonSerializersUnitTests {
|
||||
|
||||
Sample result = mapper.readValue("{ \"property\" : \"value\"}", Sample.class);
|
||||
|
||||
assertThat(result.property, is(SampleEnum.VALUE));
|
||||
assertThat(result.property).isEqualTo(SampleEnum.VALUE);
|
||||
}
|
||||
|
||||
@Test // DATAREST-929
|
||||
@@ -61,7 +62,7 @@ public class JacksonSerializersUnitTests {
|
||||
|
||||
Sample result = mapper.readValue("{ \"collection\" : [ \"value\" ] }", Sample.class);
|
||||
|
||||
assertThat(result.collection, hasItem(SampleEnum.VALUE));
|
||||
assertThat(result.collection).contains(SampleEnum.VALUE);
|
||||
}
|
||||
|
||||
@Test // DATAREST-929
|
||||
@@ -77,7 +78,7 @@ public class JacksonSerializersUnitTests {
|
||||
|
||||
Sample result = mapper.readValue("{ \"mapToEnum\" : { \"foo\" : \"value\" } }", Sample.class);
|
||||
|
||||
assertThat(result.mapToEnum.get("foo"), is(SampleEnum.VALUE));
|
||||
assertThat(result.mapToEnum.get("foo")).isEqualTo(SampleEnum.VALUE);
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
5
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JsonSchemaUnitTests.java
Normal file → Executable file
5
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/JsonSchemaUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.webmvc.json.JsonSchema.JsonSchemaProperty;
|
||||
@@ -37,7 +36,7 @@ public class JsonSchemaUnitTests {
|
||||
|
||||
JsonSchemaProperty property = new JsonSchemaProperty("foo", null, "bar", false);
|
||||
|
||||
assertThat(property.with(type.getProperty("foo")).type, is("number"));
|
||||
assertThat(property.with(type.getRequiredProperty("foo")).type).isEqualTo("number");
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
27
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappedPropertiesUnitTests.java
Normal file → Executable file
27
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappedPropertiesUnitTests.java
Normal file → Executable file
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@@ -35,37 +34,37 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
public class MappedPropertiesUnitTests {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
KeyValueMappingContext context = new KeyValueMappingContext();
|
||||
KeyValuePersistentEntity<?> entity = context.getPersistentEntity(Sample.class);
|
||||
KeyValueMappingContext<?, ?> context = new KeyValueMappingContext<>();
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(Sample.class);
|
||||
MappedProperties properties = MappedProperties.fromJacksonProperties(entity, mapper);
|
||||
|
||||
@Test // DATAREST-575
|
||||
public void doesNotExposeMappedPropertyForNonSpringDataPersistentProperty() {
|
||||
|
||||
assertThat(properties.hasPersistentPropertyForField("notExposedBySpringData"), is(false));
|
||||
assertThat(properties.getPersistentProperty("notExposedBySpringData"), is(nullValue()));
|
||||
assertThat(properties.hasPersistentPropertyForField("notExposedBySpringData")).isFalse();
|
||||
assertThat(properties.getPersistentProperty("notExposedBySpringData")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-575
|
||||
public void doesNotExposeMappedPropertyForNonJacksonProperty() {
|
||||
|
||||
assertThat(properties.hasPersistentPropertyForField("notExposedByJackson"), is(false));
|
||||
assertThat(properties.getPersistentProperty("notExposedByJackson"), is(nullValue()));
|
||||
assertThat(properties.hasPersistentPropertyForField("notExposedByJackson")).isFalse();
|
||||
assertThat(properties.getPersistentProperty("notExposedByJackson")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-575
|
||||
public void exposesProperty() {
|
||||
|
||||
assertThat(properties.hasPersistentPropertyForField("exposedProperty"), is(true));
|
||||
assertThat(properties.getPersistentProperty("exposedProperty"), is(notNullValue()));
|
||||
assertThat(properties.hasPersistentPropertyForField("exposedProperty")).isTrue();
|
||||
assertThat(properties.getPersistentProperty("exposedProperty")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-575
|
||||
public void exposesRenamedPropertyByExternalName() {
|
||||
|
||||
assertThat(properties.hasPersistentPropertyForField("email"), is(true));
|
||||
assertThat(properties.getPersistentProperty("email"), is(notNullValue()));
|
||||
assertThat(properties.getMappedName(entity.getPersistentProperty("emailAddress")), is("email"));
|
||||
assertThat(properties.hasPersistentPropertyForField("email")).isTrue();
|
||||
assertThat(properties.getPersistentProperty("email")).isNotNull();
|
||||
assertThat(properties.getMappedName(entity.getRequiredPersistentProperty("emailAddress"))).isEqualTo("email");
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
25
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java
Normal file → Executable file
25
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java
Normal file → Executable file
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -59,31 +58,31 @@ public class MappingAwarePageableArgumentResolverUnitTests {
|
||||
@Test // DATAREST-906
|
||||
public void resolveArgumentShouldReturnTranslatedPageable() throws Exception {
|
||||
|
||||
Sort translated = new Sort("world");
|
||||
Pageable pageable = new PageRequest(0, 1, Direction.ASC, "hello");
|
||||
Sort translated = Sort.by("world");
|
||||
Pageable pageable = PageRequest.of(0, 1, Direction.ASC, "hello");
|
||||
|
||||
when(delegate.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory)).thenReturn(pageable);
|
||||
when(translator.translateSort(pageable.getSort(), parameter, webRequest)).thenReturn(translated);
|
||||
|
||||
Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory);
|
||||
|
||||
assertThat(result.getPageSize(), is(1));
|
||||
assertThat(result.getPageNumber(), is(0));
|
||||
assertThat(result.getSort(), is(equalTo(translated)));
|
||||
assertThat(result.getPageSize()).isEqualTo(1);
|
||||
assertThat(result.getPageNumber()).isEqualTo(0);
|
||||
assertThat(result.getSort()).isEqualTo(translated);
|
||||
}
|
||||
|
||||
@Test // DATAREST-906
|
||||
public void resolveArgumentShouldReturnPageableWithoutSort() throws Exception {
|
||||
|
||||
Pageable pageable = new PageRequest(0, 1);
|
||||
Pageable pageable = PageRequest.of(0, 1);
|
||||
|
||||
when(delegate.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory)).thenReturn(pageable);
|
||||
|
||||
Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory);
|
||||
|
||||
assertThat(result.getPageSize(), is(1));
|
||||
assertThat(result.getPageNumber(), is(0));
|
||||
assertThat(result.getSort(), is(nullValue()));
|
||||
assertThat(result.getPageSize()).isEqualTo(1);
|
||||
assertThat(result.getPageNumber()).isEqualTo(0);
|
||||
assertThat(result.getSort()).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-906
|
||||
@@ -91,6 +90,6 @@ public class MappingAwarePageableArgumentResolverUnitTests {
|
||||
|
||||
Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory);
|
||||
|
||||
assertThat(result, is(nullValue()));
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
27
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java
Normal file → Executable file
27
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -28,7 +27,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -36,8 +35,8 @@ import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.core.util.Java8PluginRegistry;
|
||||
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.AssociationOmittingSerializerModifier;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.AssociationUriResolvingDeserializerModifier;
|
||||
@@ -49,7 +48,6 @@ import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.mvc.ResourceProcessorInvoker;
|
||||
import org.springframework.plugin.core.OrderAwarePluginRegistry;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
@@ -78,7 +76,7 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
KeyValueMappingContext mappingContext = new KeyValueMappingContext();
|
||||
KeyValueMappingContext<?, ?> mappingContext = new KeyValueMappingContext<>();
|
||||
mappingContext.getPersistentEntity(Sample.class);
|
||||
mappingContext.getPersistentEntity(SampleWithAdditionalGetters.class);
|
||||
mappingContext.getPersistentEntity(PersistentEntityJackson2ModuleUnitTests.PetOwner.class);
|
||||
@@ -89,12 +87,10 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
|
||||
NestedEntitySerializer nestedEntitySerializer = new NestedEntitySerializer(persistentEntities,
|
||||
new EmbeddedResourcesAssembler(persistentEntities, associations, mock(ExcerptProjector.class)), invoker);
|
||||
OrderAwarePluginRegistry<EntityLookup<?>, Class<?>> lookups = OrderAwarePluginRegistry.create();
|
||||
|
||||
SimpleModule module = new SimpleModule();
|
||||
|
||||
module.setSerializerModifier(new AssociationOmittingSerializerModifier(persistentEntities, associations,
|
||||
nestedEntitySerializer, new LookupObjectSerializer(lookups)));
|
||||
nestedEntitySerializer, new LookupObjectSerializer(Java8PluginRegistry.empty())));
|
||||
module.setDeserializerModifier(new AssociationUriResolvingDeserializerModifier(persistentEntities, associations,
|
||||
converter, mock(RepositoryInvokerFactory.class)));
|
||||
|
||||
@@ -110,7 +106,7 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
|
||||
String result = mapper.writeValueAsString(sample);
|
||||
|
||||
assertThat(JsonPath.read(result, "$.foo"), is((Object) "bar"));
|
||||
assertThat(JsonPath.<String> read(result, "$.foo")).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test // DATAREST-340
|
||||
@@ -119,14 +115,15 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
SampleWithAdditionalGetters sample = new SampleWithAdditionalGetters();
|
||||
|
||||
String result = mapper.writeValueAsString(sample);
|
||||
assertThat(JsonPath.read(result, "$.number"), is((Object) 5));
|
||||
|
||||
assertThat(JsonPath.<Integer> read(result, "$.number")).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test // DATAREST-662
|
||||
public void resolvesReferenceToSubtypeCorrectly() throws IOException {
|
||||
|
||||
PersistentProperty<?> property = persistentEntities.getPersistentEntity(PetOwner.class)
|
||||
.getPersistentProperty("pet");
|
||||
PersistentProperty<?> property = persistentEntities.getRequiredPersistentEntity(PetOwner.class)
|
||||
.getRequiredPersistentProperty("pet");
|
||||
|
||||
when(associations.isLinkableAssociation(property)).thenReturn(true);
|
||||
when(converter.convert(new UriTemplate("/pets/1").expand(), TypeDescriptor.valueOf(URI.class),
|
||||
@@ -134,8 +131,8 @@ public class PersistentEntityJackson2ModuleUnitTests {
|
||||
|
||||
PetOwner petOwner = mapper.readValue("{\"pet\":\"/pets/1\"}", PetOwner.class);
|
||||
|
||||
assertThat(petOwner, is(notNullValue()));
|
||||
assertThat(petOwner.getPet(), is(notNullValue()));
|
||||
assertThat(petOwner).isNotNull();
|
||||
assertThat(petOwner.getPet()).isNotNull();
|
||||
}
|
||||
|
||||
static class PetOwner {
|
||||
|
||||
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/ProjectionJacksonIntegrationTests.java
Normal file → Executable file
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/ProjectionJacksonIntegrationTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -62,7 +61,7 @@ public class ProjectionJacksonIntegrationTests {
|
||||
CustomerProjection projection = factory.createProjection(CustomerProjection.class, customer);
|
||||
|
||||
String result = mapper.writeValueAsString(projection);
|
||||
assertThat(JsonPath.read(result, "$.firstname"), is((Object) "Dave"));
|
||||
assertThat(JsonPath.<String> read(result, "$.firstname")).isEqualTo((Object) "Dave");
|
||||
}
|
||||
|
||||
@Test // DATAREST-221
|
||||
@@ -83,7 +82,7 @@ public class ProjectionJacksonIntegrationTests {
|
||||
|
||||
String result = mapper.writeValueAsString(resources);
|
||||
|
||||
assertThat(JsonPath.read(result, "$._embedded.customers[0].firstname"), is((Object) "Dave"));
|
||||
assertThat(JsonPath.<String> read(result, "$._embedded.customers[0].firstname")).isEqualTo((Object) "Dave");
|
||||
}
|
||||
|
||||
static class Customer {
|
||||
|
||||
83
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java
Normal file → Executable file
83
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -48,14 +47,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
public class SortTranslatorUnitTests {
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
KeyValueMappingContext mappingContext;
|
||||
KeyValueMappingContext<?, ?> mappingContext;
|
||||
PersistentEntities persistentEntities;
|
||||
SortTranslator sortTranslator;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
mappingContext = new KeyValueMappingContext();
|
||||
mappingContext = new KeyValueMappingContext<>();
|
||||
mappingContext.getPersistentEntity(Plain.class);
|
||||
mappingContext.getPersistentEntity(WithJsonProperty.class);
|
||||
mappingContext.getPersistentEntity(UnwrapEmbedded.class);
|
||||
@@ -70,106 +69,106 @@ public class SortTranslatorUnitTests {
|
||||
@Test // DATAREST-883
|
||||
public void shouldMapKnownProperties() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("hello", "name"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("hello", "name"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("hello"), is(nullValue()));
|
||||
assertThat(translatedSort.getOrderFor("name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("hello")).isNull();
|
||||
assertThat(translatedSort.getOrderFor("name")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-883
|
||||
public void returnsNullSortIfNoPropertiesMatch() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("hello", "world"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("hello", "world"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort, is(nullValue()));
|
||||
assertThat(translatedSort).isEqualTo(Sort.unsorted());
|
||||
}
|
||||
|
||||
@Test // DATAREST-883
|
||||
public void shouldMapKnownPropertiesWithJsonProperty() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("hello", "foo"),
|
||||
mappingContext.getPersistentEntity(WithJsonProperty.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("hello", "foo"),
|
||||
mappingContext.getRequiredPersistentEntity(WithJsonProperty.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("hello"), is(nullValue()));
|
||||
assertThat(translatedSort.getOrderFor("name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("hello")).isNull();
|
||||
assertThat(translatedSort.getOrderFor("name")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-883
|
||||
public void shouldJacksonFieldNameForMapping() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("name"),
|
||||
mappingContext.getPersistentEntity(WithJsonProperty.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("name"),
|
||||
mappingContext.getRequiredPersistentEntity(WithJsonProperty.class));
|
||||
|
||||
assertThat(translatedSort, is(nullValue()));
|
||||
assertThat(translatedSort).isEqualTo(Sort.unsorted());
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void shouldMapKnownNestedProperties() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(
|
||||
new Sort("embedded.name", "embedded.collection", "embedded.someInterface"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort.by("embedded.name", "embedded.collection", "embedded.someInterface"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("embedded.name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("embedded.collection"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("embedded.someInterface"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("embedded.name")).isNotNull();
|
||||
assertThat(translatedSort.getOrderFor("embedded.collection")).isNotNull();
|
||||
assertThat(translatedSort.getOrderFor("embedded.someInterface")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void shouldSkipWrongNestedProperties() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("embedded.unknown"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("embedded.unknown"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort, is(nullValue()));
|
||||
assertThat(translatedSort).isEqualTo(Sort.unsorted());
|
||||
}
|
||||
|
||||
@Test // DATAREST-910, DATAREST-976
|
||||
public void shouldSkipKnownAssociationProperties() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("association.name"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("association.name"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort, is(nullValue()));
|
||||
assertThat(translatedSort).isEqualTo(Sort.unsorted());
|
||||
}
|
||||
|
||||
@Test // DATAREST-976
|
||||
public void shouldMapEmbeddableAssociationProperties() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("refEmbedded.name"),
|
||||
mappingContext.getPersistentEntity(Plain.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("refEmbedded.name"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("refEmbedded.name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("refEmbedded.name")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void shouldJacksonFieldNameForNestedFieldMapping() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("em.foo"),
|
||||
mappingContext.getPersistentEntity(WithJsonProperty.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("em.foo"),
|
||||
mappingContext.getRequiredPersistentEntity(WithJsonProperty.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("embeddedWithJsonProperty.bar"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("embeddedWithJsonProperty.bar")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void shouldTranslatePathForSingleLevelJsonUnwrappedObject() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("un-name"),
|
||||
mappingContext.getPersistentEntity(UnwrapEmbedded.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("un-name"),
|
||||
mappingContext.getRequiredPersistentEntity(UnwrapEmbedded.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("embedded.name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("embedded.name")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void shouldTranslatePathForMultiLevelLevelJsonUnwrappedObject() {
|
||||
|
||||
Sort translatedSort = sortTranslator.translateSort(new Sort("un-name", "burrito.un-name"),
|
||||
mappingContext.getPersistentEntity(MultiUnwrapped.class));
|
||||
Sort translatedSort = sortTranslator.translateSort(Sort.by("un-name", "burrito.un-name"),
|
||||
mappingContext.getRequiredPersistentEntity(MultiUnwrapped.class));
|
||||
|
||||
assertThat(translatedSort.getOrderFor("anotherWrap.embedded.name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("burrito.embedded.name"), is(notNullValue()));
|
||||
assertThat(translatedSort.getOrderFor("anotherWrap.embedded.name")).isNotNull();
|
||||
assertThat(translatedSort.getOrderFor("burrito.embedded.name")).isNotNull();
|
||||
}
|
||||
|
||||
static class Plain {
|
||||
|
||||
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/UriStringDeserializerUnitTests.java
Normal file → Executable file
11
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/UriStringDeserializerUnitTests.java
Normal file → Executable file
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.net.URI;
|
||||
@@ -29,7 +28,7 @@ import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
@@ -82,8 +81,8 @@ public class UriStringDeserializerUnitTests {
|
||||
@Test // DATAREST-377
|
||||
public void returnsNullUriIfSourceIsEmptyOrNull() throws Exception {
|
||||
|
||||
assertThat(invokeConverterWith(""), is(nullValue()));
|
||||
assertThat(invokeConverterWith(null), is(nullValue()));
|
||||
assertThat(invokeConverterWith("")).isNull();
|
||||
assertThat(invokeConverterWith(null)).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-377
|
||||
|
||||
53
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/WrappedPropertiesUnitTests.java
Normal file → Executable file
53
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/WrappedPropertiesUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -46,13 +45,13 @@ public class WrappedPropertiesUnitTests {
|
||||
|
||||
static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
KeyValueMappingContext mappingContext;
|
||||
KeyValueMappingContext<?, ?> mappingContext;
|
||||
PersistentEntities persistentEntities;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
mappingContext = new KeyValueMappingContext();
|
||||
mappingContext = new KeyValueMappingContext<>();
|
||||
mappingContext.getPersistentEntity(MultiLevelNesting.class);
|
||||
mappingContext.getPersistentEntity(SyntheticProperties.class);
|
||||
|
||||
@@ -62,72 +61,72 @@ public class WrappedPropertiesUnitTests {
|
||||
@Test // DATAREST-910
|
||||
public void wrappedPropertiesShouldConsiderSingleLevelUnwrapping() {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(OneLevelNesting.class);
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getRequiredPersistentEntity(OneLevelNesting.class);
|
||||
WrappedProperties wrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, persistentEntity,
|
||||
MAPPER);
|
||||
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("street"), is(true));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("one"), is(false));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("street")).isTrue();
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("one")).isFalse();
|
||||
|
||||
List<PersistentProperty<?>> street = wrappedProperties.getPersistentProperties("street");
|
||||
|
||||
PersistentProperty<?> addressProperty = persistentEntity.getPersistentProperty("address");
|
||||
PersistentProperty<?> streetProperty = persistentEntities.getPersistentEntity(Address.class)
|
||||
.getPersistentProperty("street");
|
||||
PersistentProperty<?> addressProperty = persistentEntity.getRequiredPersistentProperty("address");
|
||||
PersistentProperty<?> streetProperty = persistentEntities.getRequiredPersistentEntity(Address.class)
|
||||
.getRequiredPersistentProperty("street");
|
||||
|
||||
assertThat(street, contains(addressProperty, streetProperty));
|
||||
assertThat(street).contains(addressProperty, streetProperty);
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void wrappedPropertiesShouldConsiderMultiLevelUnwrapping() {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(MultiLevelNesting.class);
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getRequiredPersistentEntity(MultiLevelNesting.class);
|
||||
WrappedProperties wrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, persistentEntity,
|
||||
new ObjectMapper());
|
||||
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-one-post"), is(true));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-street-post"), is(true));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("nested"), is(false));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-one-post")).isTrue();
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-street-post")).isTrue();
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("nested")).isFalse();
|
||||
|
||||
List<PersistentProperty<?>> street = wrappedProperties.getPersistentProperties("pre-street-post");
|
||||
|
||||
PersistentProperty<?> oneLevelNestingProperty = persistentEntity.getPersistentProperty("unwrapped");
|
||||
PersistentProperty<?> addressProperty = persistentEntities.getPersistentEntity(OneLevelNesting.class)
|
||||
.getPersistentProperty("address");
|
||||
PersistentProperty<?> streetProperty = persistentEntities.getPersistentEntity(Address.class)
|
||||
.getPersistentProperty("street");
|
||||
PersistentProperty<?> oneLevelNestingProperty = persistentEntity.getRequiredPersistentProperty("unwrapped");
|
||||
PersistentProperty<?> addressProperty = persistentEntities.getRequiredPersistentEntity(OneLevelNesting.class)
|
||||
.getRequiredPersistentProperty("address");
|
||||
PersistentProperty<?> streetProperty = persistentEntities.getRequiredPersistentEntity(Address.class)
|
||||
.getRequiredPersistentProperty("street");
|
||||
|
||||
assertThat(street, contains(oneLevelNestingProperty, addressProperty, streetProperty));
|
||||
assertThat(street).contains(oneLevelNestingProperty, addressProperty, streetProperty);
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void wrappedPropertiesShouldConsiderJacksonFieldNames() {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(MultiLevelNesting.class);
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getRequiredPersistentEntity(MultiLevelNesting.class);
|
||||
WrappedProperties wrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, persistentEntity,
|
||||
new ObjectMapper());
|
||||
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-zip-post"), is(true));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-zip-post")).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void wrappedPropertiesShouldIgnoreIgnoredJacksonFields() {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(MultiLevelNesting.class);
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getRequiredPersistentEntity(MultiLevelNesting.class);
|
||||
WrappedProperties wrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, persistentEntity,
|
||||
new ObjectMapper());
|
||||
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-street-ignored"), is(false));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("pre-street-ignored")).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
public void wrappedPropertiesShouldIgnoreSyntheticProperties() {
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getPersistentEntity(SyntheticProperties.class);
|
||||
PersistentEntity<?, ?> persistentEntity = persistentEntities.getRequiredPersistentEntity(SyntheticProperties.class);
|
||||
WrappedProperties wrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, persistentEntity,
|
||||
new ObjectMapper());
|
||||
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("street"), is(false));
|
||||
assertThat(wrappedProperties.hasPersistentPropertiesForField("street")).isFalse();
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
4
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/AddOperationTests.java
Normal file → Executable file
4
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/AddOperationTests.java
Normal file → Executable file
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.json.patch;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -82,6 +82,6 @@ public class AddOperationTests {
|
||||
|
||||
new AddOperation("/items/-", "Some text.").perform(todo, Todo.class);
|
||||
|
||||
assertThat(todo.getItems().get(0), is("Some text."));
|
||||
assertThat(todo.getItems().get(0)).isEqualTo("Some text.");
|
||||
}
|
||||
}
|
||||
|
||||
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/CopyOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/CopyOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/JsonPatchTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/JsonPatchTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/MoveOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/MoveOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/PathToSpelTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/PathToSpelTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/RemoveOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/RemoveOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/ReplaceOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/ReplaceOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/TestOperationTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/patch/TestOperationTests.java
Normal file → Executable file
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.data.rest.webmvc.json.patch;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author Roy Clarkson
|
||||
* @author Craig Walls
|
||||
|
||||
36
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/mapping/AssociationsUnitTests.java
Normal file → Executable file
36
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/mapping/AssociationsUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.mapping;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -26,7 +25,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
|
||||
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
|
||||
@@ -55,13 +54,13 @@ public class AssociationsUnitTests {
|
||||
|
||||
Associations associations;
|
||||
|
||||
KeyValueMappingContext mappingContext;
|
||||
KeyValueMappingContext<?, ?> mappingContext;
|
||||
ResourceMappings mappings;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mappingContext = new KeyValueMappingContext();
|
||||
this.mappingContext = new KeyValueMappingContext<>();
|
||||
this.mappingContext.getPersistentEntity(Root.class);
|
||||
|
||||
this.mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(mappingContext)));
|
||||
@@ -81,37 +80,37 @@ public class AssociationsUnitTests {
|
||||
|
||||
@Test
|
||||
public void handlesNullPropertyForLookupTypeCheck() {
|
||||
assertThat(associations.isLookupType(null), is(false));
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> associations.isLookupType(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsLookupTypeCheckToConfiguration() {
|
||||
|
||||
doReturn(Root.class).when(property).getActualType();
|
||||
assertThat(associations.isLookupType(property), is(false));
|
||||
assertThat(associations.isLookupType(property)).isFalse();
|
||||
|
||||
doReturn(true).when(configuration).isLookupType(Root.class);
|
||||
assertThat(associations.isLookupType(property), is(true));
|
||||
assertThat(associations.isLookupType(property)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsIdExposureCheckToConfiguration() {
|
||||
|
||||
doReturn(Root.class).when(entity).getType();
|
||||
assertThat(associations.isIdExposed(entity), is(false));
|
||||
assertThat(associations.isIdExposed(entity)).isFalse();
|
||||
|
||||
doReturn(true).when(configuration).isIdExposedFor(Root.class);
|
||||
assertThat(associations.isIdExposed(entity), is(true));
|
||||
assertThat(associations.isIdExposed(entity)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposesConfiguredMapping() {
|
||||
assertThat(associations.getMappings(), is(mappings));
|
||||
assertThat(associations.getMappings()).isEqualTo(mappings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forwardsMetadataLookupToMappings() {
|
||||
assertThat(associations.getMetadataFor(Root.class), is(notNullValue()));
|
||||
assertThat(associations.getMetadataFor(Root.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,8 +118,8 @@ public class AssociationsUnitTests {
|
||||
|
||||
List<Link> links = associations.getLinksFor(getAssociation(Root.class, "relatedAndExported"), new Path(""));
|
||||
|
||||
assertThat(links, hasSize(1));
|
||||
assertThat(links, hasItem(new Link("/relatedAndExported", "relatedAndExported")));
|
||||
assertThat(links).hasSize(1);
|
||||
assertThat(links).contains(new Link("/relatedAndExported", "relatedAndExported"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -128,13 +127,16 @@ public class AssociationsUnitTests {
|
||||
|
||||
List<Link> links = associations.getLinksFor(getAssociation(Root.class, "relatedButNotExported"), new Path(""));
|
||||
|
||||
assertThat(links, hasSize(0));
|
||||
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);
|
||||
KeyValuePersistentEntity<?, ? extends KeyValuePersistentProperty<?>> rootEntity = mappingContext
|
||||
.getRequiredPersistentEntity(type);
|
||||
KeyValuePersistentProperty<?> property = rootEntity.getRequiredPersistentProperty(name);
|
||||
|
||||
return new Association(property, null);
|
||||
}
|
||||
|
||||
static class Root {
|
||||
|
||||
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/DelegatingHandlerMappingUnitTests.java
Normal file → Executable file
9
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/DelegatingHandlerMappingUnitTests.java
Normal file → Executable file
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
|
||||
@@ -54,7 +54,6 @@ public class DelegatingHandlerMappingUnitTests {
|
||||
assertHandlerTriedButExceptionThrown(mapping, UnsatisfiedServletRequestParameterException.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final void assertHandlerTriedButExceptionThrown(HandlerMapping mapping, Class<? extends Exception> type)
|
||||
throws Exception {
|
||||
|
||||
@@ -66,7 +65,7 @@ public class DelegatingHandlerMappingUnitTests {
|
||||
fail(String.format("Expected %s!", type.getSimpleName()));
|
||||
|
||||
} catch (Exception o_O) {
|
||||
assertThat(o_O, is(instanceOf(type)));
|
||||
assertThat(o_O).isInstanceOf(type);
|
||||
verify(second, times(1)).getHandler(request);
|
||||
} finally {
|
||||
reset(first, second);
|
||||
|
||||
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ETagDoesntMatchExceptionUnitTests.java
Normal file → Executable file
0
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ETagDoesntMatchExceptionUnitTests.java
Normal file → Executable file
55
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ETagUnitTests.java
Normal file → Executable file
55
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ETagUnitTests.java
Normal file → Executable file
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -36,42 +35,45 @@ import org.springframework.http.HttpHeaders;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ETagUnitTests {
|
||||
|
||||
KeyValueMappingContext context = new KeyValueMappingContext();
|
||||
KeyValueMappingContext<?, ?> context = new KeyValueMappingContext<>();
|
||||
|
||||
@Test(expected = ETagDoesntMatchException.class) // DATAREST-160
|
||||
public void expectWrongEtag() throws Exception {
|
||||
|
||||
ETag eTag = ETag.from("1");
|
||||
eTag.verify(context.getPersistentEntity(Sample.class), new Sample(0L));
|
||||
eTag.verify(context.getRequiredPersistentEntity(Sample.class), new Sample(0L));
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void expectCorrectEtag() throws Exception {
|
||||
ETag.from("0").verify(context.getPersistentEntity(Sample.class), new Sample(0L));
|
||||
ETag.from("0").verify(context.getRequiredPersistentEntity(Sample.class), new Sample(0L));
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void createsETagFromVersionValue() throws Exception {
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(Sample.class);
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(Sample.class);
|
||||
ETag from = ETag.from(PersistentEntityResource.build(new Sample(0L), entity).build());
|
||||
|
||||
assertThat(from.toString(), is((Object) "\"0\""));
|
||||
assertThat(from.toString()).isEqualTo((Object) "\"0\"");
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void surroundsValueWithQuotationMarksOnToString() {
|
||||
assertThat(ETag.from("1").toString(), is("\"1\""));
|
||||
assertThat(ETag.from("1").toString()).isEqualTo("\"1\"");
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void returnsNoEtagForNullStringSource() {
|
||||
assertThat(ETag.from((String) null), is(ETag.NO_ETAG));
|
||||
assertThat(ETag.from((String) null)).isEqualTo(ETag.NO_ETAG);
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void returnsNoEtagForNullPersistentEntityResourceSource() {
|
||||
assertThat(ETag.from((PersistentEntityResource) null), is(ETag.NO_ETAG));
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
|
||||
ETag.from((PersistentEntityResource) null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
@@ -81,48 +83,49 @@ public class ETagUnitTests {
|
||||
ETag two = ETag.from("2");
|
||||
ETag nullETag = ETag.from((String) null);
|
||||
|
||||
assertThat(one.equals(one), is(true));
|
||||
assertThat(one.equals(two), is(false));
|
||||
assertThat(two.equals(one), is(false));
|
||||
assertThat(nullETag.equals(one), is(false));
|
||||
assertThat(one.equals(two), is(false));
|
||||
assertThat(one.equals(""), is(false));
|
||||
assertThat(one.equals(one)).isTrue();
|
||||
assertThat(one.equals(two)).isFalse();
|
||||
assertThat(two.equals(one)).isFalse();
|
||||
assertThat(nullETag.equals(one)).isFalse();
|
||||
assertThat(one.equals(two)).isFalse();
|
||||
assertThat(one.equals("")).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void returnsNoEtagForEntityWithoutVersionProperty() {
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(SampleWithoutVersion.class);
|
||||
assertThat(ETag.from(PersistentEntityResource.build(new SampleWithoutVersion(), entity).build()), is(ETag.NO_ETAG));
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(SampleWithoutVersion.class);
|
||||
assertThat(ETag.from(PersistentEntityResource.build(new SampleWithoutVersion(), entity).build()))
|
||||
.isEqualTo(ETag.NO_ETAG);
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void noETagReturnsNullForToString() {
|
||||
assertThat(ETag.NO_ETAG.toString(), is(nullValue()));
|
||||
assertThat(ETag.NO_ETAG.toString()).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void noETagDoesNotRejectVerification() {
|
||||
ETag.NO_ETAG.verify(context.getPersistentEntity(Sample.class), new Sample(5L));
|
||||
ETag.NO_ETAG.verify(context.getRequiredPersistentEntity(Sample.class), new Sample(5L));
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void verificationDoesNotRejectNullEntity() {
|
||||
ETag.from("5").verify(context.getPersistentEntity(Sample.class), null);
|
||||
ETag.from("5").verify(context.getRequiredPersistentEntity(Sample.class), null);
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void stripsTrailingAndLeadingQuotesOnCreation() {
|
||||
|
||||
assertThat(ETag.from("\"1\""), is(ETag.from("1")));
|
||||
assertThat(ETag.from("\"\"1\"\""), is(ETag.from("1")));
|
||||
assertThat(ETag.from("\"1\"")).isEqualTo(ETag.from("1"));
|
||||
assertThat(ETag.from("\"\"1\"\"")).isEqualTo(ETag.from("1"));
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
public void addsETagToHeadersIfNotNoETag() {
|
||||
|
||||
HttpHeaders headers = ETag.from("1").addTo(new HttpHeaders());
|
||||
assertThat(headers.getETag(), is(notNullValue()));
|
||||
assertThat(headers.getETag()).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-160
|
||||
@@ -130,7 +133,7 @@ public class ETagUnitTests {
|
||||
|
||||
HttpHeaders headers = ETag.NO_ETAG.addTo(new HttpHeaders());
|
||||
|
||||
assertThat(headers.containsKey("ETag"), is(false));
|
||||
assertThat(headers.containsKey("ETag")).isFalse();
|
||||
}
|
||||
|
||||
// tag::versioned-sample[]
|
||||
|
||||
15
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/PersistentEntityProjectorUnitTests.java
Normal file → Executable file
15
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/PersistentEntityProjectorUnitTests.java
Normal file → Executable file
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.rest.core.config.ProjectionDefinitionConfiguration;
|
||||
@@ -61,7 +60,7 @@ public class PersistentEntityProjectorUnitTests {
|
||||
|
||||
Object object = new Object();
|
||||
|
||||
assertThat(projector.project(object), is(object));
|
||||
assertThat(projector.project(object)).isEqualTo(object);
|
||||
}
|
||||
|
||||
@Test // DATAREST-221
|
||||
@@ -69,7 +68,7 @@ public class PersistentEntityProjectorUnitTests {
|
||||
|
||||
configuration.addProjection(Sample.class, Object.class);
|
||||
|
||||
assertThat(projector.project(new Object()), is(instanceOf(Sample.class)));
|
||||
assertThat(projector.project(new Object())).isInstanceOf(Sample.class);
|
||||
}
|
||||
|
||||
@Test // DATAREST-806
|
||||
@@ -77,12 +76,12 @@ public class PersistentEntityProjectorUnitTests {
|
||||
|
||||
configuration.addProjection(Sample.class, Object.class);
|
||||
|
||||
assertThat(projector.projectExcerpt(new Object()), is(instanceOf(Sample.class)));
|
||||
assertThat(projector.projectExcerpt(new Object())).isInstanceOf(Sample.class);
|
||||
}
|
||||
|
||||
@Test // DATAREST-806
|
||||
public void excerptProjectionIsUsedForExcerpt() {
|
||||
assertThat(projector.projectExcerpt(new Object()), is(instanceOf(Excerpt.class)));
|
||||
assertThat(projector.projectExcerpt(new Object())).isInstanceOf(Excerpt.class);
|
||||
}
|
||||
|
||||
@Test // DATAREST-806
|
||||
@@ -92,7 +91,7 @@ public class PersistentEntityProjectorUnitTests {
|
||||
|
||||
PersistentEntityProjector projector = new PersistentEntityProjector(configuration, factory, null, mappings);
|
||||
|
||||
assertThat(projector.projectExcerpt(new Object()), is(instanceOf(Excerpt.class)));
|
||||
assertThat(projector.projectExcerpt(new Object())).isInstanceOf(Excerpt.class);
|
||||
}
|
||||
|
||||
interface Sample {}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -84,7 +83,7 @@ public class RepositoryConstraintViolationExceptionMessageUnitTests {
|
||||
|
||||
List<ValidationError> result = message.getErrors();
|
||||
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result.get(0).getInvalidValue(), is(value));
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).getInvalidValue()).isEqualTo(value);
|
||||
}
|
||||
}
|
||||
|
||||
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/util/UriUtilsUnitTests.java
Normal file → Executable file
7
spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/util/UriUtilsUnitTests.java
Normal file → Executable file
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc.util;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
@@ -38,7 +37,7 @@ public class UriUtilsUnitTests {
|
||||
Method method = ClassUtils.getMethod(MappedMethod.class, "method");
|
||||
List<String> pathSegments = UriUtils.getPathSegments(method);
|
||||
|
||||
assertThat(pathSegments, hasItems("hello", "world"));
|
||||
assertThat(pathSegments).contains("hello", "world");
|
||||
}
|
||||
|
||||
@Test // DATAREST-910
|
||||
@@ -47,7 +46,7 @@ public class UriUtilsUnitTests {
|
||||
Method method = ClassUtils.getMethod(MappedClassAndMethod.class, "method");
|
||||
List<String> pathSegments = UriUtils.getPathSegments(method);
|
||||
|
||||
assertThat(pathSegments, hasItems("hello", "world"));
|
||||
assertThat(pathSegments).contains("hello", "world");
|
||||
}
|
||||
|
||||
static class MappedMethod {
|
||||
|
||||
Reference in New Issue
Block a user