我有一个与调用特定方法相关的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()+ "()"
做过一些研究之后,我明白我需要使用反射吗?如何实现这一目标?
答案 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");