如何使用字符串调用GWT ClientBundle接口的方法?

时间:2013-10-28 18:07:48

标签: java gwt clientbundle

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

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

做过一些研究之后,我明白我需要使用反射吗?如何实现这一目标?

2 个答案:

答案 0 :(得分:4)

MyClientBundle接口应该扩展ClientBundleWithLookup而不是ClientBundle。

ClientBundleWithLookup有一个getResource(String name)方法,允许您从资源名称(方法名称)中检索资源。

答案 1 :(得分:2)

使用注释中的图标名称缓存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");