Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 323aa60

Browse files
odrotbohmmp911de
authored andcommitted
Move RepositoryMethodContext to repository.core package.
RepositoryMethodContext are now made available for dependency injection via RepositoryConfigurationExtensionSupport.registerBeansForRoot(...). Moved RMC into repository.core package (previously repository.core.support) and only expose factory methods on DefaultRepositoryMethodContext. DRMC also exposes a injection proxy lookup method that creates a proxy equipped with a TargetSource delegating to DRMC.getInstance() (previously ....getContext()). An additional, static DRMC.forMethod(...) allows the creation of a default instance for testing purposes. Rename getRepository() to getMetadata() on RMC. Fixes #3175. Original pull request: #3176
1 parent 55afe84 commit 323aa60

File tree

8 files changed

+207
-108
lines changed

8 files changed

+207
-108
lines changed

‎src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3232
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3333
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
34+
import org.springframework.beans.factory.support.RootBeanDefinition;
3435
import org.springframework.core.annotation.AnnotationUtils;
3536
import org.springframework.core.io.ResourceLoader;
3637
import org.springframework.core.log.LogMessage;
3738
import org.springframework.dao.InvalidDataAccessApiUsageException;
3839
import org.springframework.data.repository.core.RepositoryMetadata;
40+
import org.springframework.data.repository.core.RepositoryMethodContext;
3941
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
42+
import org.springframework.data.repository.core.support.DefaultRepositoryMethodContext;
4043
import org.springframework.lang.Nullable;
4144
import org.springframework.util.Assert;
4245
import org.springframework.util.StringUtils;
@@ -109,7 +112,13 @@ public String getDefaultNamedQueryLocation() {
109112

110113
@Override
111114
public void registerBeansForRoot(BeanDefinitionRegistry registry,
112-
RepositoryConfigurationSource configurationSource) {}
115+
RepositoryConfigurationSource configurationSource) {
116+
117+
// A proxy RepositoryMethodContext for dependency injection
118+
registerIfNotAlreadyRegistered(
119+
() -> new RootBeanDefinition(RepositoryMethodContext.class, DefaultRepositoryMethodContext::getInjectionProxy),
120+
registry, "repositoryMethodContextFactory", configurationSource);
121+
}
113122

114123
/**
115124
* Returns the prefix of the module to be used to create the default location for Spring Data named queries.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.repository.core;
17+
18+
import java.lang.reflect.Method;
19+
20+
/**
21+
* Interface containing methods and value objects to obtain information about the current repository method invocation.
22+
* <p>
23+
* The {@link #currentMethod()} method is usable if the repository factory is configured to expose the current
24+
* repository method metadata (not the default). It returns the invoked repository method. Target objects or advice can
25+
* use this to make advised calls.
26+
* <p>
27+
* Spring Data's framework does not expose method metadata by default, as there is a performance cost in doing so.
28+
* <p>
29+
* The functionality in this class might be used by a target object that needed access to resources on the invocation.
30+
* However, this approach should not be used when there is a reasonable alternative, as it makes application code
31+
* dependent on usage in particular.
32+
*
33+
* @author Christoph Strobl
34+
* @author Mark Paluch
35+
* @author Oliver Drotbohm
36+
* @since 3.4.0
37+
*/
38+
public interface RepositoryMethodContext {
39+
40+
/**
41+
* Returns the metadata for the repository.
42+
*
43+
* @return the repository metadata, will never be {@literal null}.
44+
*/
45+
RepositoryMetadata getMetadata();
46+
47+
/**
48+
* Returns the current method that is being invoked.
49+
* <p>
50+
* The method object represents the method as being invoked on the repository interface. It doesn't match the backing
51+
* repository implementation in case the method invocation is delegated to an implementation method.
52+
*
53+
* @return the current method, will never be {@literal null}..
54+
*/
55+
Method getMethod();
56+
}

‎src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java‎

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,22 @@
1717

1818
import java.lang.reflect.Method;
1919

20+
import org.springframework.aop.framework.ProxyFactory;
2021
import org.springframework.core.NamedThreadLocal;
2122
import org.springframework.data.repository.core.RepositoryMetadata;
23+
import org.springframework.data.repository.core.RepositoryMethodContext;
2224
import org.springframework.lang.Nullable;
25+
import org.springframework.util.Assert;
2326

2427
/**
2528
* Class containing value objects providing information about the current repository method invocation.
2629
*
2730
* @author Christoph Strobl
2831
* @author Mark Paluch
32+
* @author Oliver Drotbohm
2933
* @since 3.4.0
3034
*/
31-
class DefaultRepositoryMethodContext implements RepositoryMethodContext {
35+
publicclass DefaultRepositoryMethodContext implements RepositoryMethodContext {
3236

3337
/**
3438
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
@@ -46,15 +50,41 @@ class DefaultRepositoryMethodContext implements RepositoryMethodContext {
4650
this.method = method;
4751
}
4852

53+
/**
54+
* Creates a new {@link RepositoryMethodContext} for the given {@link Method}.
55+
*
56+
* @param method must not be {@literal null}.
57+
* @return will never be {@literal null}.
58+
*/
59+
public static RepositoryMethodContext forMethod(Method method) {
60+
61+
Assert.notNull(method, "Method must not be null!");
62+
63+
return new DefaultRepositoryMethodContext(AbstractRepositoryMetadata.getMetadata(method.getDeclaringClass()),
64+
method);
65+
}
66+
67+
/**
68+
* Creates a proxy {@link RepositoryMethodContext} instance suitable for dependency injection.
69+
*
70+
* @return will never be {@literal null}.
71+
*/
72+
public static RepositoryMethodContext getInjectionProxy() {
73+
74+
return ProxyFactory.getProxy(RepositoryMethodContext.class,
75+
new DynamicLookupTargetSource<>(RepositoryMethodContext.class, () -> getInstance()));
76+
}
77+
4978
@Nullable
50-
static RepositoryMethodContext getMetadata() {
79+
static RepositoryMethodContext getInstance() {
5180
return currentMethod.get();
5281
}
5382

5483
@Nullable
5584
static RepositoryMethodContext setMetadata(@Nullable RepositoryMethodContext metadata) {
5685

5786
RepositoryMethodContext old = currentMethod.get();
87+
5888
if (metadata != null) {
5989
currentMethod.set(metadata);
6090
} else {
@@ -65,13 +95,12 @@ static RepositoryMethodContext setMetadata(@Nullable RepositoryMethodContext met
6595
}
6696

6797
@Override
68-
public RepositoryMetadata getRepository() {
98+
public RepositoryMetadata getMetadata() {
6999
return repositoryMetadata;
70100
}
71101

72102
@Override
73103
public Method getMethod() {
74104
return method;
75105
}
76-
77106
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.repository.core.support;
17+
18+
import java.util.function.Supplier;
19+
20+
import org.springframework.aop.TargetSource;
21+
import org.springframework.lang.NonNull;
22+
import org.springframework.lang.Nullable;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* A {@link TargetSource}, that will re-obtain an instance using the configured supplier.
27+
*
28+
* @author Oliver Drotbohm
29+
* @since 3.4.0
30+
*/
31+
class DynamicLookupTargetSource<T> implements TargetSource {
32+
33+
private final Class<T> type;
34+
private final Supplier<? extends T> supplier;
35+
36+
/**
37+
* Creates a new {@link DynamicLookupTargetSource} for the given type and {@link Supplier}.
38+
*
39+
* @param type must not be {@literal null}.
40+
* @param supplier must not be {@literal null}.
41+
*/
42+
public DynamicLookupTargetSource(Class<T> type, Supplier<? extends T> supplier) {
43+
44+
Assert.notNull(type, "Type must not be null!");
45+
Assert.notNull(supplier, "Supplier must not be null!");
46+
47+
this.type = type;
48+
this.supplier = supplier;
49+
}
50+
51+
/*
52+
* (non-Javadoc)
53+
* @see org.springframework.aop.TargetSource#isStatic()
54+
*/
55+
@Override
56+
public boolean isStatic() {
57+
return false;
58+
}
59+
60+
/*
61+
* (non-Javadoc)
62+
* @see org.springframework.aop.TargetSource#getTarget()
63+
*/
64+
@Override
65+
@Nullable
66+
public Object getTarget() throws Exception {
67+
return supplier.get();
68+
}
69+
70+
/*
71+
* (non-Javadoc)
72+
* @see org.springframework.aop.TargetSource#getTargetClass()
73+
*/
74+
@Override
75+
@NonNull
76+
public Class<?> getTargetClass() {
77+
return type;
78+
}
79+
}

‎src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import org.springframework.data.repository.core.NamedQueries;
5757
import org.springframework.data.repository.core.RepositoryInformation;
5858
import org.springframework.data.repository.core.RepositoryMetadata;
59+
import org.springframework.data.repository.core.RepositoryMethodContext;
5960
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
6061
import org.springframework.data.repository.core.support.RepositoryInvocationMulticaster.DefaultRepositoryInvocationMulticaster;
6162
import org.springframework.data.repository.core.support.RepositoryInvocationMulticaster.NoOpRepositoryInvocationMulticaster;
@@ -772,15 +773,18 @@ public ExposeMetadataInterceptor(RepositoryMetadata repositoryMetadata) {
772773
public Object invoke(MethodInvocation invocation) throws Throwable {
773774

774775
RepositoryMethodContext oldMetadata = null;
776+
775777
try {
776-
oldMetadata = RepositoryMethodContext
777-
.setCurrentMetadata(new DefaultRepositoryMethodContext(repositoryMetadata, invocation.getMethod()));
778+
779+
oldMetadata = DefaultRepositoryMethodContext
780+
.setMetadata(new DefaultRepositoryMethodContext(repositoryMetadata, invocation.getMethod()));
781+
778782
return invocation.proceed();
783+
779784
} finally {
780-
RepositoryMethodContext.setCurrentMetadata(oldMetadata);
785+
DefaultRepositoryMethodContext.setMetadata(oldMetadata);
781786
}
782787
}
783-
784788
}
785789

786790
/**

‎src/main/java/org/springframework/data/repository/core/support/RepositoryMethodContext.java‎

Lines changed: 0 additions & 94 deletions
This file was deleted.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /