我有一个与调用特定方法相关的字符串属性。
我有这个DTO,带有图标属性
public class MyDto
{
String icon; // "first", "second", "third" etc
public String getIcon()
{
return icon;
}
}
在我的界面中,我有这些方法:(GWT ClientBundle)
public interface MyClientBundle extends ClientBundle
{
@Source("icon_first.jpg")
ImageResource icon_first();
@Source("logo_second.jpg")
ImageResource icon_second();
@Source("icon_third.jpg")
ImageResource icon_third();
}
我目前正在对选择语句使用低效的查找,但想通过构建字符串来选择正确的方法:
public ImageResource getValue(MyDto object)
{
return getIconFromCode(object.getIcon());
}
private ImageResource getIconFromCode(String code)
{
if(code.equalsIgnoreCase("first"))
{
return resources.icon_first();
}
else if(code.equalsIgnoreCase("second"))
{
return resources.icon_second();
}
else if(code.equalsIgnoreCase("third"))
{
return resources.icon_third();
}
else
{
return resources.icon_default();
}
}
我想构建一个字符串来选择正确的方法,类似于"icon_" + object.getIcon()+ "()"
接口 MyClientBundle 应该扩展 ClientBundleWithLookup 而不是 ClientBundle。
ClientBundleWithLookup 有一个 getResource(字符串名称)方法,该方法允许您从资源名称(方法名称)中检索资源。
按注释中的图标名称缓存 getter 方法,并使用该缓存调用 getter。
下面的代码仅从一级接口获取注释。 如果出于某种原因需要更高,只需递归调用 cacheGettersFor() 方法即可。
这里没有检查以确保图标 getter 方法具有正确的签名(不带参数,返回 ImageResource),如果您使用此代码中的任何一个,您将需要添加它。
public class IconGetterCache {
class IconGetterCacheForBundleType {
private Map<String, Method> _iconGetters = new HashMap<>();
private Class<?> _runtimeClass;
private void cacheGettersFor(Class<?> forClazz) {
for (Method method : forClazz.getMethods()) {
Source iconSourceAnnotation = method.getAnnotation(Source.class);
if (iconSourceAnnotation != null) {
_iconGetters.put(iconSourceAnnotation.value(), method);
}
}
}
IconGetterCacheForBundleType(final Class<?> runtimeClass) {
_runtimeClass = runtimeClass;
for (Class<?> iface : _runtimeClass.getInterfaces()) {
cacheGettersFor(iface);
}
cacheGettersFor(_runtimeClass);
}
public ImageResource getIconFromBundle(ClientBundle bundle, String iconName) {
if (!_runtimeClass.isAssignableFrom(bundle.getClass())) {
throw new IllegalArgumentException("Mismatched bundle type");
}
Method getter = _iconGetters.get(iconName);
if (getter == null) { return null; }
try {
return (ImageResource) getter.invoke(bundle);
}
catch (Throwable t) {
throw new RuntimeException("Could not get icon", t);
}
}
}
private Map<Class<?>, IconGetterCacheForBundleType> _getterCaches = new HashMap<>();
//main entry point, use this to get your icons
public ImageResource getIconFromBundle(ClientBundle bundle, String iconName) {
final Class<? extends ClientBundle> getterClass = bundle.getClass();
IconGetterCacheForBundleType getterCache = _getterCaches.get(getterClass);
if (getterCache == null) {
_getterCaches.put(getterClass, getterCache = new IconGetterCacheForBundleType(getterClass));
}
return getterCache.getIconFromBundle(bundle, iconName);
}
}
//Here's how I tested
IconGetterCache gc = new IconGetterCache();
MyClientBundle concreteClientBundle = new MyClientBundle() {
@Override
public ImageResource icon_first() {
//return correct icon
}
@Override
public ImageResource icon_second() {
//return correct icon
}
@Override
public ImageResource icon_third() {
//return correct icon
}
};
gc.getIconFromBundle(concreteClientBundle, "icon_first.jpg");