DATAREST-724 - Added support for customizing the property to be used for URI generation.
Spring Data REST now exposes an EntityLookup interface that allows to customize the property of an entity that shall be used to create item resource URIs. By default this mechanism uses the backend identifier and uses the repository's findOne(…) method. The EntityLookup now exposes one method to return the property value to be used for URI generation as well as one method to obtain the entity instance from the very same raw identifier value. The EntityLookups are registered with both the SelfLinkProvider (for link creation) and the RepositoryInvoker (to obtain the entity instance).
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.plugin.core.OrderAwarePluginRegistry;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of SelfLinkProvider that uses an {@link EntityLinks} instance to create self links. Considers
|
||||
* the configured {@link EntityLookup}s to use the returned resource identifier to eventually create the link.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.5
|
||||
* @soundtrack Trio Rotation - Travis
|
||||
*/
|
||||
public class DefaultSelfLinkProvider implements SelfLinkProvider {
|
||||
|
||||
private final PersistentEntities entities;
|
||||
private final EntityLinks entityLinks;
|
||||
private final PluginRegistry<EntityLookup<?>, Class<?>> lookups;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultSelfLinkProvider} from the {@link PersistentEntities}, {@link EntityLinks} and
|
||||
* {@link EntityLookup}s.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param entityLinks must not be {@literal null}.
|
||||
* @param lookups must not be {@literal null}.
|
||||
*/
|
||||
public DefaultSelfLinkProvider(PersistentEntities entities, EntityLinks entityLinks,
|
||||
List<? extends EntityLookup<?>> lookups) {
|
||||
|
||||
Assert.notNull(entities, "PersistentEntities must not be null!");
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
Assert.notNull(lookups, "EntityLookups must not be null!");
|
||||
|
||||
this.entities = entities;
|
||||
this.entityLinks = entityLinks;
|
||||
this.lookups = OrderAwarePluginRegistry.create(lookups);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.support.SelfLinkProvider#createSelfLinkFor(java.lang.Object)
|
||||
*/
|
||||
public Link createSelfLinkFor(Object instance) {
|
||||
|
||||
Assert.notNull(instance, "Domain object must not be null!");
|
||||
|
||||
return entityLinks.linkToSingleResource(instance.getClass(), getResourceId(instance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier to be used to create the self link URI.
|
||||
*
|
||||
* @param instance must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getResourceId(Object instance) {
|
||||
|
||||
Class<? extends Object> instanceType = instance.getClass();
|
||||
|
||||
EntityLookup<Object> lookup = (EntityLookup<Object>) lookups.getPluginFor(instanceType);
|
||||
|
||||
if (lookup != null) {
|
||||
return lookup.getResourceIdentifier(instance);
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = entities.getPersistentEntity(instanceType);
|
||||
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot create self link for %s! No persistent entity found!", instanceType));
|
||||
}
|
||||
|
||||
return entity.getIdentifierAccessor(instance).getIdentifier();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.plugin.core.Plugin;
|
||||
|
||||
/**
|
||||
* SPI to customize which property of an entity is used as unique identifier and how the entity instance is looked up
|
||||
* from the backend. Prefer to extend {@link EntityLookupSupport} to let the generics declaration be used for the
|
||||
* {@link #supports(Object)} method automatically.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @see EntityLookupSupport
|
||||
* @see DefaultSelfLinkProvider
|
||||
* @since 2.5
|
||||
* @soundtrack Elephants Crossing - Echo (Live at Stadtfest Dresden -
|
||||
* https://soundcloud.com/elephants-crossing/sets/live-at-stadtfest-dresden)
|
||||
*/
|
||||
public interface EntityLookup<T> extends Plugin<Class<?>> {
|
||||
|
||||
/**
|
||||
* Returns the property of the given entity that shall be used to uniquely identify it. If no {@link EntityLookup} is
|
||||
* defined for a particular type, a standard identifier lookup mechanism (i.e. the datastore identifier) will be used
|
||||
* to eventually create an identifying URI.
|
||||
*
|
||||
* @param entity will never be {@literal null}.
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
Serializable getResourceIdentifier(T entity);
|
||||
|
||||
/**
|
||||
* Returns the entity instance to be used if an entity with the given identifier value is requested. Implementations
|
||||
* will usually forward the call to a repository method explicitly and can assume the given value be basically the
|
||||
* value they returned in {@link #getResourceIdentifier(Object)}.
|
||||
* <p>
|
||||
* Implementations are free to return {@literal null} to indicate absence of a value or wrap the result into any
|
||||
* generally supported {@code Optional} type.
|
||||
*
|
||||
* @param id will never be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
Object lookupEntity(Serializable id);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
|
||||
/**
|
||||
* {@link EntityLookup} implementation base class to derive the supported domain type from the generics signature.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.5
|
||||
* @soundtrack Elephants Crossing - The New (Live at Stadtfest Dresden -
|
||||
* https://soundcloud.com/elephants-crossing/sets/live-at-stadtfest-dresden)
|
||||
*/
|
||||
public abstract class EntityLookupSupport<T> implements EntityLookup<T> {
|
||||
|
||||
private final Class<?> domainType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityLookupSupport} instance discovering the supported type from the generics signature.
|
||||
*/
|
||||
public EntityLookupSupport() {
|
||||
this.domainType = GenericTypeResolver.resolveTypeArgument(getClass(), EntityLookup.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> delimiter) {
|
||||
return domainType.isAssignableFrom(delimiter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* Component to create self links for entity instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.5
|
||||
* @soundtrack Trio Rotation - Rotation
|
||||
*/
|
||||
public interface SelfLinkProvider {
|
||||
|
||||
/**
|
||||
* Returns the self link for the given entity instance.
|
||||
*
|
||||
* @param instance must never be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
Link createSelfLinkFor(Object instance);
|
||||
}
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -29,6 +32,8 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.plugin.core.OrderAwarePluginRegistry;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -66,8 +71,8 @@ public class UnwrappingRepositoryInvokerFactory implements RepositoryInvokerFact
|
||||
converters.add(new Converter<Object, Object>() {
|
||||
@Override
|
||||
public Object convert(Object source) {
|
||||
return source instanceof com.google.common.base.Optional ? ((com.google.common.base.Optional<?>) source)
|
||||
.orNull() : source;
|
||||
return source instanceof com.google.common.base.Optional
|
||||
? ((com.google.common.base.Optional<?>) source).orNull() : source;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -76,17 +81,20 @@ public class UnwrappingRepositoryInvokerFactory implements RepositoryInvokerFact
|
||||
}
|
||||
|
||||
private final RepositoryInvokerFactory delegate;
|
||||
private final PluginRegistry<EntityLookup<?>, Class<?>> lookups;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UnwrappingRepositoryInvokerFactory}.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
* @param lookups must not be {@literal null}.
|
||||
*/
|
||||
public UnwrappingRepositoryInvokerFactory(RepositoryInvokerFactory delegate) {
|
||||
public UnwrappingRepositoryInvokerFactory(RepositoryInvokerFactory delegate,
|
||||
List<? extends EntityLookup<?>> lookups) {
|
||||
|
||||
Assert.notNull(delegate, "Delegate RepositoryInvokerFactory must not be null!");
|
||||
Assert.notNull(lookups, "EntityLookups must not be null!");
|
||||
|
||||
this.delegate = delegate;
|
||||
this.lookups = OrderAwarePluginRegistry.create(lookups);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -95,7 +103,10 @@ public class UnwrappingRepositoryInvokerFactory implements RepositoryInvokerFact
|
||||
*/
|
||||
@Override
|
||||
public RepositoryInvoker getInvokerFor(Class<?> domainType) {
|
||||
return new UnwrappingRepositoryInvoker(delegate.getInvokerFor(domainType), CONVERTERS);
|
||||
|
||||
EntityLookup<?> lookup = lookups.getPluginFor(domainType);
|
||||
|
||||
return new UnwrappingRepositoryInvoker(delegate.getInvokerFor(domainType), CONVERTERS, lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,33 +115,20 @@ public class UnwrappingRepositoryInvokerFactory implements RepositoryInvokerFact
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
private static class UnwrappingRepositoryInvoker implements RepositoryInvoker {
|
||||
|
||||
private final RepositoryInvoker delegate;
|
||||
private final Collection<Converter<Object, Object>> converters;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UnwrappingRepositoryInvoker} for the given delegate and {@link Converter}s.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
* @param converters must not be {@literal null}.
|
||||
*/
|
||||
public UnwrappingRepositoryInvoker(RepositoryInvoker delegate, Collection<Converter<Object, Object>> converters) {
|
||||
|
||||
Assert.notNull(delegate, "Delegate RepositoryInvoker must not be null!");
|
||||
Assert.notNull(converters, "Converters must not be null!");
|
||||
|
||||
this.delegate = delegate;
|
||||
this.converters = converters;
|
||||
}
|
||||
private final @NonNull RepositoryInvoker delegate;
|
||||
private final @NonNull Collection<Converter<Object, Object>> converters;
|
||||
private final EntityLookup<?> lookup;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInvoker#invokeFindOne(java.io.Serializable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
public <T> T invokeFindOne(Serializable id) {
|
||||
return (T) postProcess(delegate.invokeFindOne(id));
|
||||
return postProcess(lookup != null ? lookup.lookupEntity(id) : delegate.invokeFindOne(id));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -231,13 +229,14 @@ public class UnwrappingRepositoryInvokerFactory implements RepositoryInvokerFact
|
||||
* @param result can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Object postProcess(Object result) {
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T postProcess(Object result) {
|
||||
|
||||
for (Converter<Object, Object> converter : converters) {
|
||||
result = converter.convert(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
return (T) result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.support;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.rest.core.domain.mongodb.Profile;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultSelfLinkProvider}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Trio Rotation - Triopane
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultSelfLinkProviderUnitTests {
|
||||
|
||||
SelfLinkProvider provider;
|
||||
|
||||
@Mock EntityLinks entityLinks;
|
||||
PersistentEntities entities;
|
||||
List<EntityLookup<?>> lookups;
|
||||
|
||||
public @Rule ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
when(entityLinks.linkToSingleResource((Class<?>) any(), any())).then(new Answer<Link>() {
|
||||
|
||||
@Override
|
||||
public Link answer(InvocationOnMock invocation) throws Throwable {
|
||||
|
||||
Class<?> type = invocation.getArgumentAt(0, Class.class);
|
||||
Serializable id = invocation.getArgumentAt(1, Serializable.class);
|
||||
|
||||
return new Link("/".concat(type.getName()).concat("/").concat(id.toString()));
|
||||
}
|
||||
});
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
context.getPersistentEntity(Profile.class);
|
||||
context.afterPropertiesSet();
|
||||
|
||||
this.entities = new PersistentEntities(Arrays.asList(context));
|
||||
this.lookups = Collections.emptyList();
|
||||
this.provider = new DefaultSelfLinkProvider(entities, entityLinks, lookups);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullEntities() {
|
||||
new DefaultSelfLinkProvider(null, entityLinks, lookups);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullEntityLinks() {
|
||||
new DefaultSelfLinkProvider(entities, null, lookups);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullEntityLookups() {
|
||||
new DefaultSelfLinkProvider(entities, entityLinks, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test
|
||||
public void usesEntityIdIfNoLookupDefined() {
|
||||
|
||||
String id = UUID.randomUUID().toString();
|
||||
Link link = provider.createSelfLinkFor(new Profile(id, "Name", "Type"));
|
||||
|
||||
assertThat(link.getHref(), Matchers.endsWith(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void usesEntityLookupIfDefined() {
|
||||
|
||||
EntityLookup<Object> lookup = mock(EntityLookup.class);
|
||||
when(lookup.supports(Profile.class)).thenReturn(true);
|
||||
when(lookup.getResourceIdentifier(any(Profile.class))).thenReturn("foo");
|
||||
|
||||
this.provider = new DefaultSelfLinkProvider(entities, entityLinks, Arrays.asList(lookup));
|
||||
|
||||
String id = UUID.randomUUID().toString();
|
||||
Link link = provider.createSelfLinkFor(new Profile(id, "Name", "Type"));
|
||||
|
||||
assertThat(link.getHref(), Matchers.endsWith("foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test
|
||||
public void rejectsLinkCreationForUnknownEntity() {
|
||||
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(Object.class.getName());
|
||||
exception.expectMessage("No persistent entity found!");
|
||||
|
||||
provider.createSelfLinkFor(new Object());
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,13 @@ package org.springframework.data.rest.core.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
@@ -33,6 +35,7 @@ import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.domain.mongodb.Profile;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -59,7 +62,7 @@ public class UnwrappingRepositoryInvokerFactoryUnitTests {
|
||||
|
||||
when(delegate.getInvokerFor(Object.class)).thenReturn(invoker);
|
||||
|
||||
this.factory = new UnwrappingRepositoryInvokerFactory(delegate);
|
||||
this.factory = new UnwrappingRepositoryInvokerFactory(delegate, Collections.<EntityLookup<?>> emptyList());
|
||||
this.method = Object.class.getMethod("toString");
|
||||
}
|
||||
|
||||
@@ -67,10 +70,10 @@ public class UnwrappingRepositoryInvokerFactoryUnitTests {
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][] { //
|
||||
{ Optional.empty(), is(nullValue()) }, //
|
||||
{ Optional.of(REFERENCE), is(REFERENCE) }, //
|
||||
{ com.google.common.base.Optional.absent(), is(nullValue()) }, //
|
||||
{ com.google.common.base.Optional.of(REFERENCE), is(REFERENCE) } //
|
||||
});
|
||||
{ Optional.of(REFERENCE), is(REFERENCE) }, //
|
||||
{ com.google.common.base.Optional.absent(), is(nullValue()) }, //
|
||||
{ com.google.common.base.Optional.of(REFERENCE), is(REFERENCE) } //
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +92,24 @@ public class UnwrappingRepositoryInvokerFactoryUnitTests {
|
||||
assertQueryValueForSource(source, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-724
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void usesRegisteredEntityLookup() {
|
||||
|
||||
EntityLookup<Object> lookup = mock(EntityLookup.class);
|
||||
when(lookup.supports(Profile.class)).thenReturn(true);
|
||||
|
||||
when(delegate.getInvokerFor(Profile.class)).thenReturn(invoker);
|
||||
|
||||
factory = new UnwrappingRepositoryInvokerFactory(delegate, Arrays.asList(lookup));
|
||||
factory.getInvokerFor(Profile.class).invokeFindOne(1L);
|
||||
|
||||
verify(lookup, times(1)).lookupEntity(eq(1L));
|
||||
}
|
||||
|
||||
private void assertFindOneValueForSource(Object source, Matcher<Object> value) {
|
||||
|
||||
when(invoker.invokeFindOne(1L)).thenReturn(source);
|
||||
@@ -98,8 +119,7 @@ public class UnwrappingRepositoryInvokerFactoryUnitTests {
|
||||
private void assertQueryValueForSource(Object source, Matcher<Object> value) {
|
||||
|
||||
when(invoker.invokeQueryMethod(method, new LinkedMultiValueMap<String, Object>(), null, null)).thenReturn(source);
|
||||
assertThat(
|
||||
factory.getInvokerFor(Object.class).invokeQueryMethod(method, new LinkedMultiValueMap<String, Object>(), null,
|
||||
null), value);
|
||||
assertThat(factory.getInvokerFor(Object.class).invokeQueryMethod(method, new LinkedMultiValueMap<String, Object>(),
|
||||
null, null), value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user