2929import java .util .stream .Collectors ;
3030import java .util .stream .Stream ;
3131
32+ import com .fasterxml .jackson .databind .ObjectMapper ;
3233import io .swagger .v3 .oas .models .OpenAPI ;
3334import org .springdoc .api .AbstractOpenApiResource ;
3435import org .springdoc .core .RepositoryRestResourceProvider ;
3536import org .springdoc .core .fn .RouterOperation ;
37+ import org .springdoc .data .rest .core .ControllerType ;
3638import org .springdoc .data .rest .core .DataRestRepository ;
3739import org .springdoc .data .rest .core .DataRestRouterOperationBuilder ;
3840
41+ import org .springframework .data .mapping .PersistentEntity ;
42+ import org .springframework .data .mapping .PersistentProperty ;
43+ import org .springframework .data .mapping .SimpleAssociationHandler ;
44+ import org .springframework .data .mapping .context .PersistentEntities ;
3945import org .springframework .data .repository .support .Repositories ;
4046import org .springframework .data .rest .core .mapping .MethodResourceMapping ;
4147import org .springframework .data .rest .core .mapping .ResourceMappings ;
4551import org .springframework .data .rest .webmvc .ProfileController ;
4652import org .springframework .data .rest .webmvc .RepositoryRestHandlerMapping ;
4753import org .springframework .data .rest .webmvc .alps .AlpsController ;
54+ import org .springframework .data .rest .webmvc .json .JacksonMetadata ;
4855import org .springframework .data .rest .webmvc .mapping .Associations ;
4956import org .springframework .data .rest .webmvc .support .DelegatingHandlerMapping ;
5057import org .springframework .web .method .HandlerMethod ;
@@ -102,6 +109,16 @@ public class SpringRepositoryRestResourceProvider implements RepositoryRestResou
102109 */
103110 private DataRestRouterOperationBuilder dataRestRouterOperationBuilder ;
104111
112+ /**
113+ * The Persistent entities.
114+ */
115+ private PersistentEntities persistentEntities ;
116+
117+ /**
118+ * The Mapper.
119+ */
120+ private ObjectMapper mapper ;
121+
105122 /**
106123 * Instantiates a new Spring repository rest resource provider.
107124 *
@@ -110,14 +127,17 @@ public class SpringRepositoryRestResourceProvider implements RepositoryRestResou
110127 * @param associations the associations
111128 * @param delegatingHandlerMapping the delegating handler mapping
112129 * @param dataRestRouterOperationBuilder the data rest router operation builder
130+ * @param persistentEntities the persistent entities
131+ * @param mapper the mapper
113132 */
114- public SpringRepositoryRestResourceProvider (ResourceMappings mappings , Repositories repositories , Associations associations ,
115- DelegatingHandlerMapping delegatingHandlerMapping , DataRestRouterOperationBuilder dataRestRouterOperationBuilder ) {
133+ public SpringRepositoryRestResourceProvider (ResourceMappings mappings , Repositories repositories , Associations associations , DelegatingHandlerMapping delegatingHandlerMapping , DataRestRouterOperationBuilder dataRestRouterOperationBuilder , PersistentEntities persistentEntities , ObjectMapper mapper ) {
116134 this .mappings = mappings ;
117135 this .repositories = repositories ;
118136 this .associations = associations ;
119137 this .delegatingHandlerMapping = delegatingHandlerMapping ;
120138 this .dataRestRouterOperationBuilder = dataRestRouterOperationBuilder ;
139+ this .persistentEntities = persistentEntities ;
140+ this .mapper = mapper ;
121141 }
122142
123143 public List <RouterOperation > getRouterOperations (OpenAPI openAPI ) {
@@ -127,18 +147,38 @@ public List<RouterOperation> getRouterOperations(OpenAPI openAPI) {
127147 Class <?> repository = repositories .getRequiredRepositoryInformation (domainType ).getRepositoryInterface ();
128148 DataRestRepository dataRestRepository = new DataRestRepository (domainType , repository );
129149 ResourceMetadata resourceMetadata = mappings .getMetadataFor (domainType );
150+ final PersistentEntity <?, ?> entity = persistentEntities .getRequiredPersistentEntity (domainType );
151+ final JacksonMetadata jackson = new JacksonMetadata (mapper , domainType );
152+
130153 if (resourceMetadata .isExported ()) {
131154 for (HandlerMapping handlerMapping : handlerMappingList ) {
132155 if (handlerMapping instanceof RepositoryRestHandlerMapping ) {
133156 RepositoryRestHandlerMapping repositoryRestHandlerMapping = (RepositoryRestHandlerMapping ) handlerMapping ;
134157 Map <RequestMappingInfo , HandlerMethod > handlerMethodMap = repositoryRestHandlerMapping .getHandlerMethods ();
158+ // Entity controllers lookup first
135159 Map <RequestMappingInfo , HandlerMethod > handlerMethodMapFiltered = handlerMethodMap .entrySet ().stream ()
136160 .filter (requestMappingInfoHandlerMethodEntry -> REPOSITORY_ENTITY_CONTROLLER .equals (requestMappingInfoHandlerMethodEntry
137- .getValue ().getBeanType ().getName ()) || REPOSITORY_PROPERTY_CONTROLLER .equals (requestMappingInfoHandlerMethodEntry
138161 .getValue ().getBeanType ().getName ()))
139162 .filter (controller -> !AbstractOpenApiResource .isHiddenRestControllers (controller .getValue ().getBeanType ()))
140163 .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (a1 , a2 ) -> a1 ));
164+ dataRestRepository .setControllerType (ControllerType .ENTITY );
141165 findControllers (routerOperationList , handlerMethodMapFiltered , resourceMetadata , dataRestRepository , openAPI );
166+
167+ Map <RequestMappingInfo , HandlerMethod > handlerMethodMapFilteredMethodMap = handlerMethodMap .entrySet ().stream ()
168+ .filter (requestMappingInfoHandlerMethodEntry -> REPOSITORY_PROPERTY_CONTROLLER .equals (requestMappingInfoHandlerMethodEntry
169+ .getValue ().getBeanType ().getName ()))
170+ .filter (controller -> !AbstractOpenApiResource .isHiddenRestControllers (controller .getValue ().getBeanType ()))
171+ .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (a1 , a2 ) -> a1 ));
172+
173+ entity .doWithAssociations ((SimpleAssociationHandler ) association -> {
174+ PersistentProperty <?> property = association .getInverse ();
175+ if (jackson .isExported (property ) && associations .isLinkableAssociation (property )) {
176+ ResourceMetadata targetTypeMetadata = associations .getMetadataFor (property .getActualType ());
177+ dataRestRepository .setRelationName (targetTypeMetadata .getItemResourceRel ().toString ());
178+ dataRestRepository .setControllerType (ControllerType .PROPERTY );
179+ findControllers (routerOperationList , handlerMethodMapFilteredMethodMap , resourceMetadata , dataRestRepository , openAPI );
180+ }
181+ });
142182 }
143183 else if (handlerMapping instanceof BasePathAwareHandlerMapping ) {
144184 BasePathAwareHandlerMapping beanBasePathAwareHandlerMapping = (BasePathAwareHandlerMapping ) handlerMapping ;
@@ -148,7 +188,7 @@ else if (handlerMapping instanceof BasePathAwareHandlerMapping) {
148188 .getValue ().getBeanType ().getName ()))
149189 .filter (controller -> !AbstractOpenApiResource .isHiddenRestControllers (controller .getValue ().getBeanType ()))
150190 .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (a1 , a2 ) -> a1 ));
151-
191+ dataRestRepository . setControllerType ( ControllerType . SCHEMA );
152192 findControllers (routerOperationList , handlerMethodMapFiltered , resourceMetadata , dataRestRepository , openAPI );
153193 handlerMethodMapFiltered = handlerMethodMap .entrySet ().stream ()
154194 .filter (requestMappingInfoHandlerMethodEntry -> ProfileController .class .equals (requestMappingInfoHandlerMethodEntry
0 commit comments