Skip to content

Commit cf3b328

Browse files
committed
Spring Data Rest: Relations to exported Repositories are handled as if they were embedded. fixes #1084
1 parent 48886b4 commit cf3b328

16 files changed

+501
-249
lines changed

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/SpringDocDataRestConfiguration.java

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springdoc.data.rest.core.DataRestTagsService;
4545
import org.springdoc.data.rest.customisers.DataRestDelegatingMethodParameterCustomizer;
4646
import org.springdoc.data.rest.customisers.QuerydslPredicateOperationCustomizer;
47+
import org.springdoc.data.rest.utils.SpringDocDataRestUtils;
4748

4849
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4950
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -68,13 +69,14 @@
6869
import org.springframework.data.rest.webmvc.mapping.Associations;
6970
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
7071
import org.springframework.data.rest.webmvc.support.ETag;
72+
import org.springframework.hateoas.server.LinkRelationProvider;
7173

7274
import static org.springdoc.core.Constants.SPRINGDOC_ENABLED;
7375
import static org.springdoc.core.SpringDocUtils.getConfig;
7476

7577
/**
7678
* The type Spring doc data rest configuration.
77-
* @author bnasslahsen
79+
* @author bnasslashen
7880
*/
7981
@Lazy(false)
8082
@Configuration(proxyBeanMethods = false)
@@ -97,7 +99,7 @@ public class SpringDocDataRestConfiguration {
9799
@ConditionalOnMissingBean
98100
@Lazy(false)
99101
DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer(Optional<SpringDataWebProperties> optionalSpringDataWebProperties, Optional<RepositoryRestConfiguration> optionalRepositoryRestConfiguration) {
100-
return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebProperties,optionalRepositoryRestConfiguration);
102+
return new DataRestDelegatingMethodParameterCustomizer(optionalSpringDataWebProperties, optionalRepositoryRestConfiguration);
101103
}
102104

103105
/**
@@ -111,14 +113,14 @@ DelegatingMethodParameterCustomizer delegatingMethodParameterCustomizer(Optional
111113
@ConditionalOnMissingBean
112114
@Primary
113115
@Lazy(false)
114-
DataRestHalProvider halProvider(Optional<RepositoryRestConfiguration> repositoryRestConfiguration,Optional<HateoasProperties> hateoasPropertiesOptional) {
115-
return new DataRestHalProvider(repositoryRestConfiguration,hateoasPropertiesOptional);
116+
DataRestHalProvider halProvider(Optional<RepositoryRestConfiguration> repositoryRestConfiguration, Optional<HateoasProperties> hateoasPropertiesOptional) {
117+
return new DataRestHalProvider(repositoryRestConfiguration, hateoasPropertiesOptional);
116118
}
117119

118120

119121
/**
120122
* The type Querydsl provider.
121-
* @author bnasslahsen
123+
* @author bnasslashen
122124
*/
123125
@ConditionalOnClass(value = { QuerydslBindingsFactory.class })
124126
class QuerydslProvider {
@@ -143,7 +145,7 @@ QuerydslPredicateOperationCustomizer queryDslQuerydslPredicateOperationCustomize
143145

144146
/**
145147
* The type Spring repository rest resource provider configuration.
146-
* @author bnasslahsen
148+
* @author bnasslashen
147149
*/
148150
@Lazy(false)
149151
@Configuration(proxyBeanMethods = false)
@@ -163,7 +165,7 @@ static class SpringRepositoryRestResourceProviderConfiguration {
163165
* @param repositories the repositories
164166
* @param associations the associations
165167
* @param applicationContext the application context
166-
* @param dataRestRouterOperationService the data rest router operation builder
168+
* @param dataRestRouterOperationService the data rest router operation service
167169
* @param persistentEntities the persistent entities
168170
* @param mapper the mapper
169171
* @return the spring repository rest resource provider
@@ -174,18 +176,18 @@ SpringRepositoryRestResourceProvider springRepositoryRestResourceProvider(Resour
174176
Repositories repositories, Associations associations, ApplicationContext applicationContext,
175177
DataRestRouterOperationService dataRestRouterOperationService, PersistentEntities persistentEntities,
176178
ObjectMapper mapper) {
177-
return new SpringRepositoryRestResourceProvider(mappings,repositories, associations, applicationContext,
178-
dataRestRouterOperationService, persistentEntities, mapper);
179+
return new SpringRepositoryRestResourceProvider(mappings, repositories, associations, applicationContext,
180+
dataRestRouterOperationService, persistentEntities, mapper);
179181
}
180182

181183
/**
182-
* Data rest router operation builder data rest router operation builder.
184+
* Data rest router operation builder data rest router operation service.
183185
*
184-
* @param dataRestOperationService the data rest operation builder
186+
* @param dataRestOperationService the data rest operation service
185187
* @param springDocConfigProperties the spring doc config properties
186188
* @param repositoryRestConfiguration the repository rest configuration
187189
* @param dataRestHalProvider the data rest hal provider
188-
* @return the data rest router operation builder
190+
* @return the data rest router operation service
189191
*/
190192
@Bean
191193
@ConditionalOnMissingBean
@@ -207,7 +209,7 @@ DataRestRouterOperationService dataRestRouterOperationBuilder(DataRestOperationS
207209
@ConditionalOnMissingBean
208210
DataRestOperationService dataRestOperationBuilder(DataRestRequestService dataRestRequestService, DataRestTagsService tagsBuilder,
209211
DataRestResponseService dataRestResponseService, OperationService operationService) {
210-
return new DataRestOperationService(dataRestRequestService, tagsBuilder, dataRestResponseService,operationService);
212+
return new DataRestOperationService(dataRestRequestService, tagsBuilder, dataRestResponseService, operationService);
211213
}
212214

213215
/**
@@ -217,26 +219,28 @@ DataRestOperationService dataRestOperationBuilder(DataRestRequestService dataRes
217219
* @param parameterBuilder the parameter builder
218220
* @param requestBodyService the request body builder
219221
* @param requestBuilder the request builder
222+
* @param springDocDataRestUtils the spring doc data rest utils
220223
* @return the data rest request builder
221224
*/
222225
@Bean
223226
@ConditionalOnMissingBean
224227
DataRestRequestService dataRestRequestBuilder(LocalVariableTableParameterNameDiscoverer localSpringDocParameterNameDiscoverer, GenericParameterService parameterBuilder,
225-
RequestBodyService requestBodyService, AbstractRequestService requestBuilder) {
228+
RequestBodyService requestBodyService, AbstractRequestService requestBuilder,SpringDocDataRestUtils springDocDataRestUtils) {
226229
return new DataRestRequestService(localSpringDocParameterNameDiscoverer, parameterBuilder,
227-
requestBodyService, requestBuilder);
230+
requestBodyService, requestBuilder, springDocDataRestUtils);
228231
}
229232

230233
/**
231234
* Data rest response builder data rest response builder.
232235
*
233236
* @param genericResponseService the generic response builder
237+
* @param springDocDataRestUtils the spring doc data rest utils
234238
* @return the data rest response builder
235239
*/
236240
@Bean
237241
@ConditionalOnMissingBean
238-
DataRestResponseService dataRestResponseBuilder(GenericResponseService genericResponseService) {
239-
return new DataRestResponseService(genericResponseService);
242+
DataRestResponseService dataRestResponseBuilder(GenericResponseService genericResponseService, SpringDocDataRestUtils springDocDataRestUtils) {
243+
return new DataRestResponseService(genericResponseService, springDocDataRestUtils);
240244
}
241245

242246
/**
@@ -250,6 +254,18 @@ DataRestResponseService dataRestResponseBuilder(GenericResponseService genericRe
250254
DataRestTagsService dataRestTagsBuilder(OpenAPIService openAPIService) {
251255
return new DataRestTagsService(openAPIService);
252256
}
257+
258+
/**
259+
* Spring doc data rest utils spring doc data rest utils.
260+
*
261+
* @param linkRelationProvider the link relation provider
262+
* @return the spring doc data rest utils
263+
*/
264+
@Bean
265+
@ConditionalOnMissingBean
266+
SpringDocDataRestUtils springDocDataRestUtils(LinkRelationProvider linkRelationProvider) {
267+
return new SpringDocDataRestUtils(linkRelationProvider);
268+
}
253269
}
254270

255271
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/SpringRepositoryRestResourceProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ public List<RouterOperation> getRouterOperations(OpenAPI openAPI) {
181181
DataRestRepository dataRestRepository = new DataRestRepository(domainType, repository);
182182
ResourceMetadata resourceMetadata = mappings.getMetadataFor(domainType);
183183
final PersistentEntity<?, ?> entity = persistentEntities.getRequiredPersistentEntity(domainType);
184+
dataRestRepository.setPersistentEntity(entity);
184185
final JacksonMetadata jackson = new JacksonMetadata(mapper, domainType);
185186

186187
if (resourceMetadata.isExported()) {
@@ -339,7 +340,8 @@ private void findSearchResourceMappings(OpenAPI openAPI, List<RouterOperation> r
339340
* @return the list
340341
*/
341342
private List<RouterOperation> findSearchControllers(List<RouterOperation> routerOperationList,
342-
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap, ResourceMetadata resourceMetadata, DataRestRepository dataRestRepository, OpenAPI openAPI, SearchResourceMappings searchResourceMappings) {
343+
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap, ResourceMetadata resourceMetadata, DataRestRepository dataRestRepository,
344+
OpenAPI openAPI, SearchResourceMappings searchResourceMappings) {
343345
Stream<MethodResourceMapping> methodResourceMappingStream = searchResourceMappings.getExportedMappings();
344346
methodResourceMappingStream.forEach(methodResourceMapping -> dataRestRouterOperationService.buildSearchRouterOperationList(
345347
routerOperationList, handlerMethodMap, resourceMetadata, dataRestRepository, openAPI, methodResourceMapping));

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestOperationService.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public class DataRestOperationService {
9595
* @param dataRestRequestService the data rest request builder
9696
* @param tagsBuilder the tags builder
9797
* @param dataRestResponseService the data rest response builder
98+
* @param operationService the operation service
9899
*/
99100
public DataRestOperationService(DataRestRequestService dataRestRequestService, DataRestTagsService tagsBuilder,
100101
DataRestResponseService dataRestResponseService, OperationService operationService) {
@@ -130,7 +131,7 @@ public Operation buildOperation(HandlerMethod handlerMethod, DataRestRepository
130131
}
131132
else if (ControllerType.SEARCH.equals(controllerType)) {
132133
operation = buildSearchOperation(handlerMethod, dataRestRepository, openAPI, requestMethod,
133-
methodAttributes, methodResourceMapping);
134+
methodAttributes, methodResourceMapping, resourceMetadata);
134135
}
135136
return operation;
136137
}
@@ -154,7 +155,7 @@ private Operation buildEntityOperation(HandlerMethod handlerMethod, DataRestRepo
154155
if (!ControllerType.GENERAL.equals(dataRestRepository.getControllerType()))
155156
domainType = dataRestRepository.getDomainType();
156157
Operation operation = initOperation(handlerMethod, domainType, requestMethod);
157-
dataRestRequestService.buildParameters(domainType, openAPI, handlerMethod, requestMethod, methodAttributes, operation, resourceMetadata);
158+
dataRestRequestService.buildParameters(openAPI, handlerMethod, requestMethod, methodAttributes, operation, resourceMetadata, dataRestRepository);
158159
dataRestResponseService.buildEntityResponse(operation, handlerMethod, openAPI, requestMethod, operationPath, domainType, methodAttributes, dataRestRepository, resourceMetadata);
159160
tagsBuilder.buildEntityTags(operation, handlerMethod, dataRestRepository);
160161
if (domainType != null)
@@ -171,11 +172,12 @@ private Operation buildEntityOperation(HandlerMethod handlerMethod, DataRestRepo
171172
* @param requestMethod the request method
172173
* @param methodAttributes the method attributes
173174
* @param methodResourceMapping the method resource mapping
175+
* @param resourceMetadata the resource metadata
174176
* @return the operation
175177
*/
176178
private Operation buildSearchOperation(HandlerMethod handlerMethod, DataRestRepository dataRestRepository,
177179
OpenAPI openAPI, RequestMethod requestMethod, MethodAttributes methodAttributes,
178-
MethodResourceMapping methodResourceMapping) {
180+
MethodResourceMapping methodResourceMapping, ResourceMetadata resourceMetadata) {
179181
Class<?> domainType = dataRestRepository.getDomainType();
180182
Operation operation = initOperation(handlerMethod, domainType, requestMethod);
181183

@@ -193,7 +195,7 @@ private Operation buildSearchOperation(HandlerMethod handlerMethod, DataRestRepo
193195
HandlerMethod repositoryHandlerMethod = new HandlerMethod(methodResourceMapping.getMethod().getDeclaringClass(), methodResourceMapping.getMethod());
194196
MethodParameter[] parameters = repositoryHandlerMethod.getMethodParameters();
195197
for (MethodParameter methodParameter : parameters) {
196-
dataRestRequestService.buildCommonParameters(domainType, openAPI, requestMethod, methodAttributes, operation, new String[] { methodParameter.getParameterName() }, new MethodParameter[] { methodParameter });
198+
dataRestRequestService.buildCommonParameters(openAPI, requestMethod, methodAttributes, operation, new String[] { methodParameter.getParameterName() }, new MethodParameter[] { methodParameter }, resourceMetadata, dataRestRepository);
197199
}
198200
}
199201

@@ -222,9 +224,10 @@ private Operation buildSearchOperation(HandlerMethod handlerMethod, DataRestRepo
222224
if (methodResourceMapping.isPagingResource()) {
223225
MethodParameter[] parameters = handlerMethod.getMethodParameters();
224226
Arrays.stream(parameters).filter(methodParameter -> DefaultedPageable.class.equals(methodParameter.getParameterType())).findAny()
225-
.ifPresent(methodParameterPage -> dataRestRequestService.buildCommonParameters(domainType, openAPI, requestMethod, methodAttributes, operation, new String[] { methodParameterPage.getParameterName() }, new MethodParameter[] { methodParameterPage }));
227+
.ifPresent(methodParameterPage -> dataRestRequestService.buildCommonParameters(openAPI, requestMethod, methodAttributes, operation,
228+
new String[] { methodParameterPage.getParameterName() }, new MethodParameter[] { methodParameterPage }, resourceMetadata, dataRestRepository));
226229
}
227-
dataRestResponseService.buildSearchResponse(operation, handlerMethod, openAPI, methodResourceMapping, domainType, methodAttributes);
230+
dataRestResponseService.buildSearchResponse(operation, handlerMethod, openAPI, methodResourceMapping, domainType, methodAttributes, resourceMetadata, dataRestRepository);
228231
tagsBuilder.buildSearchTags(operation, handlerMethod, dataRestRepository, method);
229232
return operation;
230233
}
@@ -307,8 +310,10 @@ private void addOperationDescription(Operation operation, RequestMethod requestM
307310
/**
308311
* Create description.
309312
*
313+
* @param action the action
310314
* @param entity the entity
311315
* @param dataRestRepository the data rest repository
316+
* @return the string
312317
*/
313318
private String createDescription( String action, String entity, DataRestRepository dataRestRepository) {
314319
String description;

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestRepository.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
package org.springdoc.data.rest.core;
2525

26+
import org.springframework.data.mapping.PersistentEntity;
27+
2628
/**
2729
* The type Data rest repository.
2830
* @author bnasslahsen
@@ -64,6 +66,11 @@ public class DataRestRepository {
6466
*/
6567
private Class<?> propertyType;
6668

69+
/**
70+
* The Persistent entity.
71+
*/
72+
PersistentEntity<?, ?> persistentEntity;
73+
6774
/**
6875
* Instantiates a new Data rest repository.
6976
*
@@ -81,7 +88,9 @@ public DataRestRepository(Class<?> domainType, Class<?> repositoryType) {
8188
* @return the domain type
8289
*/
8390
public Class<?> getDomainType() {
84-
return domainType;
91+
if (!ControllerType.GENERAL.equals(controllerType))
92+
return domainType;
93+
return null;
8594
}
8695

8796
/**
@@ -200,4 +209,39 @@ public Class<?> getPropertyType() {
200209
public void setPropertyType(Class<?> propertyType) {
201210
this.propertyType = propertyType;
202211
}
212+
213+
/**
214+
* Gets persistent entity.
215+
*
216+
* @return the persistent entity
217+
*/
218+
public PersistentEntity<?, ?> getPersistentEntity() {
219+
return persistentEntity;
220+
}
221+
222+
/**
223+
* Sets persistent entity.
224+
*
225+
* @param persistentEntity the persistent entity
226+
*/
227+
public void setPersistentEntity(PersistentEntity<?, ?> persistentEntity) {
228+
this.persistentEntity = persistentEntity;
229+
}
230+
231+
/**
232+
* Gets return type.
233+
*
234+
* @return the return type
235+
*/
236+
public Class getReturnType() {
237+
Class returnedEntityType = domainType;
238+
239+
if (ControllerType.PROPERTY.equals(controllerType))
240+
returnedEntityType = propertyType;
241+
242+
else if (ControllerType.GENERAL.equals(controllerType))
243+
returnedEntityType = null;
244+
245+
return returnedEntityType;
246+
}
203247
}

0 commit comments

Comments
 (0)