如何使用字符串调用 GWT 客户端捆绑接口的方法



我有一个与调用特定方法相关的字符串属性。

我有这个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");

最新更新