From 3b667b90be5bd53b817cedf0ccf95858e40e02ed Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 7 Aug 2024 13:54:40 +0200 Subject: [PATCH] Update documentation and fix nullable annotations. Original Pull Request: #3093 --- .../repositories/custom-implementations.adoc | 46 +++++++++++++++---- .../DefaultRepositoryMethodContext.java | 8 ++-- .../support/RepositoryFactoryBeanSupport.java | 2 + .../support/RepositoryFactorySupport.java | 9 ++-- .../core/support/RepositoryMethodContext.java | 1 + 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/main/antora/modules/ROOT/pages/repositories/custom-implementations.adoc b/src/main/antora/modules/ROOT/pages/repositories/custom-implementations.adoc index 94048b432..a3867d511 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/custom-implementations.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/custom-implementations.adoc @@ -296,14 +296,9 @@ class DefaultSearchExtension implements SearchExtension { ---- ==== -In the snipped above we use `RepositoryMethodMetadata.get()` to get hold of metadata for the actual method invocation. In doing so we can access additional information attached to the repository. In this case we use the repositories domain type to identify the name of the index to be searched. +In the snipped above we use `RepositoryMethodContext.currentMethod()` to get hold of metadata for the actual method invocation. In doing so we can access additional information attached to the repository. In this case we use the repositories domain type to identify the name of the index to be searched. -[TIP] -==== -For testing you can use `TransactionSynchronizationManager.bindResource(RepositoryMethodMetadata.class, metadata)` to provide repository method metadata. -==== - -Now that we've got both, the fragments declaration and implementation we can register it in the `META-INF/spring.factories` file, package things up if needed and we're good to go. +Now that we've got both, the fragments declaration and implementation we can register it in the `META-INF/spring.factories` file, package things up if needed and we're almost good to go. ==== [source,properties] @@ -312,8 +307,41 @@ com.acme.search.SearchExtension=com.acme.search.DefaultSearchExtension ---- ==== -To make use of the extension simply add the interface to the repository as shown below. -The infrastructure will take care placing the required `RepositoryMethodContext` so all that +Since we're using additional metadata, that comes with additional cost, via `RepositoryMethodContext.currentMethod()` we need to advise the repository factory responsible for creating the actual repository to expose method metadata by setting the `exposeMetadata` flag. + +==== +[source,java] +---- +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; +import org.springframework.lang.Nullable; + +@Configuration +class Cfg implements BeanPostProcessor { + + @Bean + public BeanPostProcessor exposeMethodMetadata() { + + return new BeanPostProcessor() { + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) { + + if(bean instanceof RepositoryFactoryBeanSupport factoryBean) { + factoryBean.setExposeMetadata(true); + } + } + }; + } +} +---- +The above snippet outlines how to set the `exposeMetadata` flag using a `BeanPostProcessor`. +Please do not just copy/paste the above but think about your actual use case which may require a more fine grained approach as the above will simply enable the flag on each and every repository. You may want to have a look at our https://github.com/spring-projects/spring-data-examples/tree/main/bom[spring-data-examples] project to draw inspiration. +==== + +Now we are ready to make use of the extension. +Simply add the interface to the repository. ==== [source,java] diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java index 5d1ed1e27..8f87c1678 100644 --- a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java +++ b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java @@ -26,6 +26,7 @@ import org.springframework.lang.Nullable; * * @author Christoph Strobl * @author Mark Paluch + * @since 3.4.0 */ class DefaultRepositoryMethodContext implements RepositoryMethodContext { @@ -39,18 +40,19 @@ class DefaultRepositoryMethodContext implements RepositoryMethodContext { private final RepositoryMetadata repositoryMetadata; private final Method method; - public DefaultRepositoryMethodContext(RepositoryMetadata repositoryMetadata, Method method) { + DefaultRepositoryMethodContext(RepositoryMetadata repositoryMetadata, Method method) { + this.repositoryMetadata = repositoryMetadata; this.method = method; } @Nullable - public static RepositoryMethodContext getMetadata() { + static RepositoryMethodContext getMetadata() { return currentMethod.get(); } @Nullable - public static RepositoryMethodContext setMetadata(@Nullable RepositoryMethodContext metadata) { + static RepositoryMethodContext setMetadata(@Nullable RepositoryMethodContext metadata) { RepositoryMethodContext old = currentMethod.get(); if (metadata != null) { diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java index 950b3cba9..b1a8f155f 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java @@ -115,6 +115,8 @@ public abstract class RepositoryFactoryBeanSupport, *

* Default is "false", in order to avoid unnecessary extra interception. This means that no guarantees are provided * that {@code RepositoryMethodContext} access will work consistently within any method of the advised object. + * + * @since 3.4.0 */ public void setExposeMetadata(boolean exposeMetadata) { this.exposeMetadata = exposeMetadata; diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java index 4a026beae..88965a4ab 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java @@ -30,8 +30,6 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.jetbrains.annotations.NotNull; - import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; import org.springframework.beans.BeanUtils; @@ -129,8 +127,10 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, * retrieval via the {@code RepositoryMethodContext} class. This is useful if an advised object needs to obtain * repository information. *

- * Default is "false", in order to avoid unnecessary extra interception. This means that no guarantees are provided + * Default is {@literal "false"}, in order to avoid unnecessary extra interception. This means that no guarantees are provided * that {@code RepositoryMethodContext} access will work consistently within any method of the advised object. + * + * @since 3.4.0 */ public void setExposeMetadata(boolean exposeMetadata) { this.exposeMetadata = exposeMetadata; @@ -665,7 +665,8 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, @Nullable @Override - public Object invoke(@NotNull MethodInvocation invocation) throws Throwable { + public Object invoke(MethodInvocation invocation) throws Throwable { + RepositoryMethodContext oldMetadata = null; try { oldMetadata = RepositoryMethodContext diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodContext.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodContext.java index 4c28b0ef8..516c8d95b 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodContext.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodContext.java @@ -35,6 +35,7 @@ import org.springframework.lang.Nullable; * * @author Christoph Strobl * @author Mark Paluch + * @since 3.4.0 */ public interface RepositoryMethodContext {