Properly handle associations in nested entities.

Nested entities that contain a reference to an aggregate root get a link to that attached to their representation. Previously, the creation of those links assumed that the reference is a materialized instance of the remote aggregate. That's now altered to be able to deal with associations, use identifiers directly or materialize to an intermediate aggregate instance to potentially use a custom lookup.
This commit is contained in:
Oliver Drotbohm
2021-04-07 16:46:31 +02:00
parent 20cb33512e
commit 21ed68262f
11 changed files with 98 additions and 37 deletions

View File

@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
@@ -66,7 +67,8 @@ public abstract class AbstractControllerIntegrationTests {
public PersistentEntityResourceAssembler persistentEntityResourceAssembler(PersistentEntities entities,
EntityLinks entityLinks, Associations associations) {
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(entities, entityLinks, Collections.emptyList());
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(entities, entityLinks, Collections.emptyList(),
new DefaultConversionService());
return new PersistentEntityResourceAssembler(entities, StubProjector.INSTANCE, associations,
selfLinkProvider);

View File

@@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.DefaultRepositoryInvokerFactory;
@@ -112,7 +113,7 @@ public class RepositoryTestsConfig {
EntityLinks entityLinks = new RepositoryEntityLinks(repositories(), mappings, config(),
mock(PagingAndSortingTemplateVariables.class), PluginRegistry.of(DefaultIdConverter.INSTANCE));
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(persistentEntities(), entityLinks,
Collections.<EntityLookup<?>> emptyList());
Collections.<EntityLookup<?>> emptyList(), new DefaultConversionService());
DefaultRepositoryInvokerFactory invokerFactory = new DefaultRepositoryInvokerFactory(repositories());
UriToEntityConverter uriToEntityConverter = new UriToEntityConverter(persistentEntities(), invokerFactory,

View File

@@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.DefaultRepositoryInvokerFactory;
@@ -36,7 +37,6 @@ import org.springframework.data.rest.core.config.ProjectionDefinitionConfigurati
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.RepositoryResourceMappings;
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
import org.springframework.data.rest.core.support.EntityLookup;
import org.springframework.data.rest.core.support.SelfLinkProvider;
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
import org.springframework.data.rest.webmvc.jpa.Person;
@@ -120,7 +120,7 @@ public class RepositoryTestsConfig {
EntityLinks entityLinks = new RepositoryEntityLinks(repositories(), mappings, config(),
mock(PagingAndSortingTemplateVariables.class), PluginRegistry.of(DefaultIdConverter.INSTANCE));
SelfLinkProvider selfLinkProvider = new DefaultSelfLinkProvider(persistentEntities(), entityLinks,
Collections.<EntityLookup<?>> emptyList());
Collections.emptyList(), new DefaultConversionService());
DefaultRepositoryInvokerFactory invokerFactory = new DefaultRepositoryInvokerFactory(repositories());
UriToEntityConverter uriToEntityConverter = new UriToEntityConverter(persistentEntities(), invokerFactory,

View File

@@ -25,6 +25,8 @@ import java.util.Collections;
import org.junit.Test;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
import org.springframework.data.rest.tests.AbstractControllerIntegrationTests;
@@ -33,9 +35,9 @@ import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
import org.springframework.data.rest.tests.mongodb.User;
import org.springframework.data.rest.webmvc.mapping.Associations;
import org.springframework.data.rest.webmvc.support.Projector;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.test.context.ContextConfiguration;
/**
@@ -57,8 +59,9 @@ public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractC
when(projector.projectExcerpt(any())).thenAnswer(new ReturnsArgumentAt(0));
ConversionService conversionService = new DefaultConversionService();
PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, projector,
associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.emptyList()));
associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.emptyList(), conversionService));
User user = new User();
user.id = BigInteger.valueOf(4711);

View File

@@ -51,6 +51,7 @@ import org.springframework.web.context.request.ServletWebRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;
/**
* Integration tests for entity (de)serialization.
@@ -129,7 +130,9 @@ public class PersistentEntitySerializationTests {
PersistentEntityResource resource = PersistentEntityResource
.build(dave, repositories.getPersistentEntity(User.class)).build();
assertThat(JsonPath.parse(mapper.writeValueAsString(resource)).read("$.colleaguesMap.carter._links.user.href",
String.class)).isNotNull();
String result = mapper.writeValueAsString(resource);
ReadContext document = JsonPath.parse(result);
assertThat(document.read("$.colleaguesMap.carter._links.user.href", String.class)).isNotNull();
}
}