com.yahoo.collections.MethodCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vespajlib Show documentation
Show all versions of vespajlib Show documentation
Library for use in Java components of Vespa. Shared code which do
not fit anywhere else.
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.collections;
import com.yahoo.concurrent.CopyOnWriteHashMap;
import java.lang.reflect.Method;
import java.util.function.Consumer;
/**
* This will cache methods solved by reflection as reflection is expensive.
* Note that if the bundle from which the method is removed/changed you might have
* a problem... A ClassCastException might be one indication. Then clearing the cache and retrying it
* once to see if it goes away might be a solution.
* @author baldersheim
*/
public final class MethodCache {
private final String methodName;
private final CopyOnWriteHashMap, Method>> cache = new CopyOnWriteHashMap<>();
public MethodCache(String methodName) {
this.methodName = methodName;
}
/*
Clear all cached methods. Might be a wise thing to do, if you have cached some methods
that have changed due to new bundles being reloaded.
*/
public void clear() {
cache.clear();
}
public Method get(Object object) {
return get(object, null);
}
public Method get(Object object, Consumer onPut) {
Pair, Method> pair = cache.get(object.getClass().getName());
// When changing bundles, you might end up having cached the old method pointing to the old bundle.
// That will then lead to a class cast exception when invoking the wrong clone method.
// Whenever we detect a new class with the same name, we therefore drop the entire cache.
// This is also the reason for caching the pair of method and original class—not just the method.
if (pair != null && pair.getFirst() != object.getClass()) {
cache.clear();
pair = null;
}
Method method = pair == null ? null : pair.getSecond();
if (pair == null) {
method = lookupMethod(object);
cache.put(object.getClass().getName(), new Pair<>(object.getClass(), method));
if (onPut != null)
onPut.accept(object.getClass().getName());
}
return method;
}
private Method lookupMethod(Object object) {
try {
return object.getClass().getMethod(methodName);
} catch (NoSuchMethodException e) {
return null;
}
}
}