
io.lettuce.core.dynamic.DefaultRedisCommandsMetadata Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lettuce-core Show documentation
Show all versions of lettuce-core Show documentation
Advanced and thread-safe Java Redis client for synchronous, asynchronous, and
reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs
and much more.
The newest version!
package io.lettuce.core.dynamic;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import io.lettuce.core.internal.LettuceAssert;
/**
* Default implementation of {@link RedisCommandsMetadata}.
*
* @author Mark Paluch
* @since 5.0
*/
class DefaultRedisCommandsMetadata implements RedisCommandsMetadata {
/** The package separator character: '.' */
private static final char PACKAGE_SEPARATOR = '.';
private final Class> apiInterface;
/**
* Create {@link DefaultRedisCommandsMetadata} given a {@link Class command interface}.
*
* @param apiInterface must not be {@code null}.
*/
DefaultRedisCommandsMetadata(Class> apiInterface) {
this.apiInterface = apiInterface;
}
@Override
public Class> getCommandsInterface() {
return apiInterface;
}
@Override
public Collection getMethods() {
Set result = new HashSet();
for (Method method : getCommandsInterface().getMethods()) {
method = getMostSpecificMethod(method, getCommandsInterface());
if (isQueryMethodCandidate(method)) {
result.add(method);
}
}
return Collections.unmodifiableSet(result);
}
/**
* Checks whether the given method is a query method candidate.
*
* @param method
* @return
*/
private boolean isQueryMethodCandidate(Method method) {
return !method.isBridge() && !method.isDefault() && !Modifier.isStatic(method.getModifiers());
}
@Override
public A getAnnotation(Class annotationClass) {
return getCommandsInterface().getAnnotation(annotationClass);
}
@Override
public boolean hasAnnotation(Class extends Annotation> annotationClass) {
return getCommandsInterface().getAnnotation(annotationClass) != null;
}
/**
* Given a method, which may come from an interface, and a target class used in the current reflective invocation, find the
* corresponding target method if there is one. E.g. the method may be {@code IFoo.bar()} and the target class may be
* {@code DefaultFoo}. In this case, the method may be {@code DefaultFoo.bar()}. This enables attributes on that method to
* be found.
*
* @param method the method to be invoked, which may come from an interface
* @param targetClass the target class for the current invocation. May be {@code null} or may not even implement the method.
* @return the specific target method, or the original method if the {@code targetClass} doesn't implement it or is
* {@code null}
*/
public static Method getMostSpecificMethod(Method method, Class> targetClass) {
if (method != null && isOverridable(method, targetClass) && targetClass != null
&& targetClass != method.getDeclaringClass()) {
try {
try {
return targetClass.getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException ex) {
return method;
}
} catch (SecurityException ex) {
}
}
return method;
}
/**
* Determine whether the given method is overridable in the given target class.
*
* @param method the method to check
* @param targetClass the target class to check against
*/
private static boolean isOverridable(Method method, Class> targetClass) {
if (Modifier.isPrivate(method.getModifiers())) {
return false;
}
if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {
return true;
}
return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
}
/**
* Determine the name of the package of the given class, e.g. "java.lang" for the {@code java.lang.String} class.
*
* @param clazz the class
* @return the package name, or the empty String if the class is defined in the default package
*/
private static String getPackageName(Class> clazz) {
LettuceAssert.notNull(clazz, "Class must not be null");
return getPackageName(clazz.getName());
}
/**
* Determine the name of the package of the given fully-qualified class name, e.g. "java.lang" for the
* {@code java.lang.String} class name.
*
* @param fqClassName the fully-qualified class name
* @return the package name, or the empty String if the class is defined in the default package
*/
private static String getPackageName(String fqClassName) {
LettuceAssert.notNull(fqClassName, "Class name must not be null");
int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy