1

I have a String property that relates to calling a particular method.

I have this DTO, with an icon property

public class MyDto
{
    String icon; // "first", "second", "third" etc

    public String getIcon()
    { 
         return icon;
    }
}

In my interface I have these methods: (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();
}

I'm currently using an inefficient lookup with selection statements, but want to select the right method by building a string instead:

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();
    }
}

I want to build a string to select the right method instead, something like "icon_" + object.getIcon()+ "()"

Having done some research I understand I need to use reflection? How would this be accomplished?

4

2 回答 2

4

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

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

于 2013-10-29T14:53:29.887 回答
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");
于 2013-10-28T19:10:59.750 回答