Skip to content

Commit

Permalink
Polishing.
Browse files Browse the repository at this point in the history
Avoid nullability in RepositoryMethodContextHolder.getContext(). Introduce shortcut in RepositoryMethodContext to obtain the current thread-local context.
  • Loading branch information
mp911de committed Oct 16, 2024
1 parent 6e9e325 commit be34301
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,24 @@
* @author Christoph Strobl
* @author Mark Paluch
* @author Oliver Drotbohm
* @since 3.4.0
* @since 3.4
*/
public interface RepositoryMethodContext {

/**
* Try to return the current repository method metadata. This method is usable only if the calling method has been
* invoked via a repository method, and the repository factory has been set to expose metadata. Otherwise, this method
* will throw an IllegalStateException.
*
* @return the current repository method metadata (never returns {@code null})
* @throws IllegalStateException if the repository method metadata cannot be found, because the method was invoked
* outside a repository method invocation context, or because the repository has not been configured to
* expose its metadata.
*/
static RepositoryMethodContext getContext() throws IllegalStateException {
return RepositoryMethodContextHolder.getContext();
}

/**
* Returns the metadata for the repository.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,74 +19,68 @@
import org.springframework.lang.Nullable;

/**
* Associates a given {@link RepositoryMethodContext} with the current execution thread.
* <p>
* This class provides a series of static methods that interact with a thread-local storage of
* {@link RepositoryMethodContext}. The purpose of the class is to provide a convenient way to be used for an
* application.
*
* @author Christoph Strobl
* @since 3.4.0
* @author Mark Paluch
* @since 3.4
* @see RepositoryMethodContext
*/
public class RepositoryMethodContextHolder {

private static ContextProvider contextSupplier;

static {
contextSupplier = new ThreadLocalContextProvider();
}

/**
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
* "exposeMetadata" property on the controlling repository factory configuration has been set to {@code true}.
*/
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
"Current Repository Method");

/**
* Make the given repository method metadata available via the {@link #getContext()} method.
* <p>
* Note that the caller should be careful to keep the old value as appropriate.
*
* @param context the metadata to expose (or {@code null} to reset it)
* @return the old metadata, which may be {@code null} if none was bound
* @see #getContext()
*/
@Nullable
public static RepositoryMethodContext setContext(@Nullable RepositoryMethodContext context) {
return contextSupplier.set(context);
}

@Nullable
public static RepositoryMethodContext current() {
return contextSupplier.get();
}

public static void clearContext() {
contextSupplier.clear();
}

interface ContextProvider {

@Nullable
RepositoryMethodContext get();

@Nullable
RepositoryMethodContext set(@Nullable RepositoryMethodContext context);

void clear();
}

static class ThreadLocalContextProvider implements ContextProvider {

/**
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
* "exposeMetadata" property on the controlling repository factory configuration has been set to "true".
*/
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
"Current Repository Method");

@Override
@Nullable
public RepositoryMethodContext get() {
return currentMethod.get();
}

public void clear() {
RepositoryMethodContext old = currentMethod.get();
if (context != null) {
currentMethod.set(context);
} else {
currentMethod.remove();
}

@Override
@Nullable
public RepositoryMethodContext set(@Nullable RepositoryMethodContext context) {

RepositoryMethodContext old = currentMethod.get();

if (context != null) {
currentMethod.set(context);
} else {
currentMethod.remove();
}
return old;
}

return old;
/**
* Try to return the current repository method metadata. This method is usable only if the calling method has been
* invoked via a repository method, and the repository factory has been set to expose metadata. Otherwise, this method
* will throw an IllegalStateException.
*
* @return the current repository method metadata (never returns {@code null})
* @throws IllegalStateException if the repository method metadata cannot be found, because the method was invoked
* outside a repository method invocation context, or because the repository has not been configured to
* expose its metadata.
*/
public static RepositoryMethodContext getContext() {

RepositoryMethodContext metadata = currentMethod.get();

if (metadata == null) {
throw new IllegalStateException(
"Cannot find current repository method: Set 'exposeMetadata' property on RepositoryFactorySupport to 'true' to make it available, and "
+ "ensure that RepositoryMethodContext.currentMethod() is invoked in the same thread as the repository invocation.");
}

return metadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* @author Christoph Strobl
* @author Mark Paluch
* @author Oliver Drotbohm
* @since 3.4.0
* @since 3.4
*/
public class DefaultRepositoryMethodContext implements RepositoryMethodContext {

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void setRepositoryBaseClass(Class<?> repositoryBaseClass) {
* 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
* @since 3.4
*/
public void setExposeMetadata(boolean exposeMetadata) {
this.exposeMetadata = exposeMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void capturesRepositoryMetadata() {
record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocation) {}

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

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

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

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

0 comments on commit be34301

Please sign in to comment.