Skip to content

Commit be34301

Browse files
committed
Polishing.
Avoid nullability in RepositoryMethodContextHolder.getContext(). Introduce shortcut in RepositoryMethodContext to obtain the current thread-local context.
1 parent 6e9e325 commit be34301

File tree

6 files changed

+70
-141
lines changed

6 files changed

+70
-141
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,24 @@
3333
* @author Christoph Strobl
3434
* @author Mark Paluch
3535
* @author Oliver Drotbohm
36-
* @since 3.4.0
36+
* @since 3.4
3737
*/
3838
public interface RepositoryMethodContext {
3939

40+
/**
41+
* Try to return the current repository method metadata. This method is usable only if the calling method has been
42+
* invoked via a repository method, and the repository factory has been set to expose metadata. Otherwise, this method
43+
* will throw an IllegalStateException.
44+
*
45+
* @return the current repository method metadata (never returns {@code null})
46+
* @throws IllegalStateException if the repository method metadata cannot be found, because the method was invoked
47+
* outside a repository method invocation context, or because the repository has not been configured to
48+
* expose its metadata.
49+
*/
50+
static RepositoryMethodContext getContext() throws IllegalStateException {
51+
return RepositoryMethodContextHolder.getContext();
52+
}
53+
4054
/**
4155
* Returns the metadata for the repository.
4256
*

src/main/java/org/springframework/data/repository/core/RepositoryMethodContextHolder.java

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,74 +19,68 @@
1919
import org.springframework.lang.Nullable;
2020

2121
/**
22+
* Associates a given {@link RepositoryMethodContext} with the current execution thread.
23+
* <p>
24+
* This class provides a series of static methods that interact with a thread-local storage of
25+
* {@link RepositoryMethodContext}. The purpose of the class is to provide a convenient way to be used for an
26+
* application.
27+
*
2228
* @author Christoph Strobl
23-
* @since 3.4.0
29+
* @author Mark Paluch
30+
* @since 3.4
31+
* @see RepositoryMethodContext
2432
*/
2533
public class RepositoryMethodContextHolder {
2634

27-
private static ContextProvider contextSupplier;
28-
29-
static {
30-
contextSupplier = new ThreadLocalContextProvider();
31-
}
32-
35+
/**
36+
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
37+
* "exposeMetadata" property on the controlling repository factory configuration has been set to {@code true}.
38+
*/
39+
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
40+
"Current Repository Method");
41+
42+
/**
43+
* Make the given repository method metadata available via the {@link #getContext()} method.
44+
* <p>
45+
* Note that the caller should be careful to keep the old value as appropriate.
46+
*
47+
* @param context the metadata to expose (or {@code null} to reset it)
48+
* @return the old metadata, which may be {@code null} if none was bound
49+
* @see #getContext()
50+
*/
3351
@Nullable
3452
public static RepositoryMethodContext setContext(@Nullable RepositoryMethodContext context) {
35-
return contextSupplier.set(context);
36-
}
37-
38-
@Nullable
39-
public static RepositoryMethodContext current() {
40-
return contextSupplier.get();
41-
}
42-
43-
public static void clearContext() {
44-
contextSupplier.clear();
45-
}
46-
47-
interface ContextProvider {
48-
49-
@Nullable
50-
RepositoryMethodContext get();
5153

52-
@Nullable
53-
RepositoryMethodContext set(@Nullable RepositoryMethodContext context);
54-
55-
void clear();
56-
}
57-
58-
static class ThreadLocalContextProvider implements ContextProvider {
59-
60-
/**
61-
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
62-
* "exposeMetadata" property on the controlling repository factory configuration has been set to "true".
63-
*/
64-
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
65-
"Current Repository Method");
66-
67-
@Override
68-
@Nullable
69-
public RepositoryMethodContext get() {
70-
return currentMethod.get();
71-
}
72-
73-
public void clear() {
54+
RepositoryMethodContext old = currentMethod.get();
55+
if (context != null) {
56+
currentMethod.set(context);
57+
} else {
7458
currentMethod.remove();
7559
}
7660

77-
@Override
78-
@Nullable
79-
public RepositoryMethodContext set(@Nullable RepositoryMethodContext context) {
80-
81-
RepositoryMethodContext old = currentMethod.get();
82-
83-
if (context != null) {
84-
currentMethod.set(context);
85-
} else {
86-
currentMethod.remove();
87-
}
61+
return old;
62+
}
8863

89-
return old;
64+
/**
65+
* Try to return the current repository method metadata. This method is usable only if the calling method has been
66+
* invoked via a repository method, and the repository factory has been set to expose metadata. Otherwise, this method
67+
* will throw an IllegalStateException.
68+
*
69+
* @return the current repository method metadata (never returns {@code null})
70+
* @throws IllegalStateException if the repository method metadata cannot be found, because the method was invoked
71+
* outside a repository method invocation context, or because the repository has not been configured to
72+
* expose its metadata.
73+
*/
74+
public static RepositoryMethodContext getContext() {
75+
76+
RepositoryMethodContext metadata = currentMethod.get();
77+
78+
if (metadata == null) {
79+
throw new IllegalStateException(
80+
"Cannot find current repository method: Set 'exposeMetadata' property on RepositoryFactorySupport to 'true' to make it available, and "
81+
+ "ensure that RepositoryMethodContext.currentMethod() is invoked in the same thread as the repository invocation.");
9082
}
83+
84+
return metadata;
9185
}
9286
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* @author Christoph Strobl
2828
* @author Mark Paluch
2929
* @author Oliver Drotbohm
30-
* @since 3.4.0
30+
* @since 3.4
3131
*/
3232
public class DefaultRepositoryMethodContext implements RepositoryMethodContext {
3333

src/main/java/org/springframework/data/repository/core/support/DynamicLookupTargetSource.java

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

src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void setRepositoryBaseClass(Class<?> repositoryBaseClass) {
121121
* Default is "false", in order to avoid unnecessary extra interception. This means that no guarantees are provided
122122
* that {@code RepositoryMethodContext} access will work consistently within any method of the advised object.
123123
*
124-
* @since 3.4.0
124+
* @since 3.4
125125
*/
126126
public void setExposeMetadata(boolean exposeMetadata) {
127127
this.exposeMetadata = exposeMetadata;

src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ void capturesRepositoryMetadata() {
256256
record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocation) {}
257257

258258
when(factory.queryOne.execute(any(Object[].class)))
259-
.then(invocation -> new Metadata(RepositoryMethodContextHolder.current(),
259+
.then(invocation -> new Metadata(RepositoryMethodContextHolder.getContext(),
260260
ExposeInvocationInterceptor.currentInvocation()));
261261

262262
factory.setExposeMetadata(true);
@@ -279,7 +279,7 @@ record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocati
279279
}
280280

281281
when(factory.queryOne.execute(any(Object[].class)))
282-
.then(invocation -> new Metadata(RepositoryMethodContextHolder.current(),
282+
.then(invocation -> new Metadata(RepositoryMethodContextHolder.getContext(),
283283
ExposeInvocationInterceptor.currentInvocation()));
284284

285285
var repository = factory.getRepository(ObjectRepository.class, new RepositoryMetadataAccess() {});

0 commit comments

Comments
 (0)