DATAREST-1008 - Adapt to API changes in Spring Data Commons, Java 8 upgrades and Mockito 2.7.

This commit is contained in:
Oliver Gierke
2017-03-01 12:30:47 +01:00
parent 272dc179ad
commit b9957d1a6c
159 changed files with 2230 additions and 2220 deletions

View File

@@ -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());
}
}

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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)).//

View File

@@ -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);

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);
}
}

View File

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

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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}

View File

@@ -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));
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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") };
}
}
}

View File

@@ -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) {

View File

@@ -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;
}

View File

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

View File

@@ -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()));

View File

@@ -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());

View File

@@ -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);
}
}

View File

@@ -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)));
}
}

View File

@@ -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(),

View 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 {

View 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"));
}
}

View 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");
}
}

View 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);
}
}

View 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();
}
}

View 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();
}
}

View 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 {}

View 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);

View 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);
}
}

View 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

View 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);
}
}

View 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

View 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;

View File

@@ -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());
}
}

View 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

View 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;
}

View 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 {

View 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 {

View 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 {

View 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 {

View 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 {

View 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();
}
}

View 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 {

View 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 {

View 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 {

View 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

View 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

View 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.");
}
}

View 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

View 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 {

View 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);

View 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[]

View 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 {}

View File

@@ -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);
}
}

View 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 {