|
19 | 19 | import org.springframework.lang.Nullable; |
20 | 20 |
|
21 | 21 | /** |
| 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 | + * |
22 | 28 | * @author Christoph Strobl |
23 | | - * @since 3.4.0 |
| 29 | + * @author Mark Paluch |
| 30 | + * @since 3.4 |
| 31 | + * @see RepositoryMethodContext |
24 | 32 | */ |
25 | 33 | public class RepositoryMethodContextHolder { |
26 | 34 |
|
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 | + */ |
33 | 51 | @Nullable |
34 | 52 | 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(); |
51 | 53 |
|
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 { |
74 | 58 | currentMethod.remove(); |
75 | 59 | } |
76 | 60 |
|
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 | + } |
88 | 63 |
|
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."); |
90 | 82 | } |
| 83 | + |
| 84 | + return metadata; |
91 | 85 | } |
92 | 86 | } |
0 commit comments