在groovy中获得vs getProperty
让我感到惊讶!
根据groovy的文档,groovy可以使用“getProperty”方法来获取对象的属性.因此,当我想改变获取特殊对象的属性的行为时,我使用类别类来覆盖“getProperty”方法.但是,它不起作用. 这是类别类. class DynaBeanExtension { public static void setProperty(DynaBean bean,String propertyName,def newValue) { try { PropertyUtilsBean pu = null; if (bean instanceof CustomWrapDynaBean) { pu = bean.propertyUtilsBean; } if (pu != null) { pu.setProperty(bean,propertyName,newValue); } else { PropertyUtils.setProperty(bean,newValue); } } catch (IllegalArgumentException ex) { bean.propertyMissing(propertyName,newValue); } } public static def getProperty(DynaBean bean,String propertyName) { try { PropertyUtilsBean pu = null; if (bean instanceof CustomWrapDynaBean) { pu = bean.propertyUtilsBean; } if (pu != null) { return pu.getProperty(bean,propertyName); } else { return PropertyUtils.getProperty(bean,propertyName); } } catch (IllegalArgumentException ex) { return bean.propertyMissing(propertyName); } } public static def get(DynaBean bean,propertyName); } } catch (IllegalArgumentException ex) { return bean.propertyMissing(propertyName); } } 这是测试代码: public static class TestSubClass { private final int e = 3,f = 4; private final Map<String,Object> m = new HashMap<>(); public int getE() { return e; } public int getF() { return f; } public Map<String,Object> getM() { return m; } @Override public String toString() { return "TestSubClass{" + "e=" + e + ",f=" + f + ",m=" + m + '}'; } } public static class TestClass { private final int a = 1; private final TestSubClass b = new TestSubClass(); public int getA() { return a; } public TestSubClass getB() { return b; } @Override public String toString() { return "TestClass{" + "a=" + a + ",b=" + b + '}'; } } Map<String,String> pMap = new HashMap<>(); pMap.put("b.e","c"); PropertyUtilsBean pu = new PropertyUtilsBean(); pu.setResolver(new ExResolver(pMap)); TestClass testObj = new TestClass(); DynaBean bean = new CustomWrapDynaBean(testObj,pu); int c = use(DynaBeanExtension) { bean.c; } 这是ExResolver的代码: public class ExResolver implements Resolver { private static final char NESTED = '.'; private static final char MAPPED_START = '('; private static final char MAPPED_END = ')'; private static final char INDEXED_START = '['; private static final char INDEXED_END = ']'; private final Resolver resolver; private final Map<String,String> pMap; public ExResolver(Map<String,String> pMap) { this(new DefaultResolver(),pMap); } public ExResolver(Resolver resolver,Map<String,String> pMap) { this.resolver = resolver; this.pMap = new HashMap<>(pMap); } private String resolveExpr(String expression) { for (Map.Entry<String,String> entry : pMap.entrySet()) { if (expression.startsWith(entry.getValue())) { String to = entry.getValue(); if (expression.length() == entry.getValue().length()) { return entry.getKey(); } else { int toTest = expression.codePointAt(to.length()); if (toTest == NESTED || toTest == MAPPED_START || toTest == INDEXED_START) { return entry.getKey() + expression.substring(to.length(),expression.length()); } else { return expression; } } } } return expression; } @Override public int getIndex(String expression) { expression = resolveExpr(expression); return resolver.getIndex(expression); } @Override public String getKey(String expression) { expression = resolveExpr(expression); return resolver.getKey(expression); } @Override public String getProperty(String expression) { expression = resolveExpr(expression); return resolver.getProperty(expression); } @Override public boolean hasNested(String expression) { expression = resolveExpr(expression); return resolver.hasNested(expression); } @Override public boolean isIndexed(String expression) { expression = resolveExpr(expression); return resolver.isIndexed(expression); } @Override public boolean isMapped(String expression) { expression = resolveExpr(expression); return resolver.isMapped(expression); } @Override public String next(String expression) { expression = resolveExpr(expression); return resolver.next(expression); } @Override public String remove(String expression) { expression = resolveExpr(expression); return resolver.remove(expression); } } 调用“get”,而不是“getProperty” 更重要的是,在实际情况下,DynaBeanExtension是用groovy编译的. bean的构造是用java编译的.然后通过使用绑定,我把它放入测试代码,这是由java代码执行的运行时脚本. 解决方法
这发生在编译本身.让我们看一个更简单的例子.
class Main { static void main(def args) { Foo foo = new Foo() foo.str = "" foo.str } } 对于Groovy类 class Foo { String str } 如果你反编译Main类,你会看到它 public class Main implements GroovyObject { public Main() { Main this; CallSite[] arrayOfCallSite = $getCallSiteArray(); MetaClass localMetaClass = $getStaticMetaClass(); this.metaClass = localMetaClass; } public static void main(String... args) { CallSite[] arrayOfCallSite = $getCallSiteArray(); Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class),Foo.class); String str = ""; ScriptBytecodeAdapter.setGroovyObjectProperty(str,Main.class,foo,(String)"str"); arrayOfCallSite[1].callGroovyObjectGetProperty(foo); } } A. [property] = call被编译为ScriptBytecodeAdapter.setGroovyObjectProperty,后者又调用链MetaClassImpl.setProperty> MetaMethod.doMethodInvoke> CachedMethod.invoke> java.lang.reflect.Method.invoke> [设定器] 并且.[property]调用被编译为arrayOfCallSite [1] .callGroovyObjectGetProperty,然后调用链 对于Java类 如果你使用被调用的类的Java版本,就像这样 public class Foo { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } } 相同的Main反编译为 public class Main implements GroovyObject { public Main() { Main this; CallSite[] arrayOfCallSite = $getCallSiteArray(); MetaClass localMetaClass = $getStaticMetaClass(); this.metaClass = localMetaClass; } public static void main(String... args) { CallSite[] arrayOfCallSite = $getCallSiteArray(); Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class),Foo.class); String str = ""; ScriptBytecodeAdapter.setProperty(str,null,(String)"str"); arrayOfCallSite[1].callGetProperty(foo); } } A. [property] = call被编译为ScriptBytecodeAdapter.setProperty,后者又调用链[Class] .setProperty> InvokerHelper.setProperty – > MetaClassImpl.setProperty> MetaMethod.doMethodInvoke> CachedMethod.invoke> java.lang.reflect.Method.invoke> [设定器] 并且.[property]调用被编译为arrayOfCallSite [1] .callGroovyObjectGetProperty,然后调用链 要更正您的代码 正如您从这些调度链中看到的那样,您已正确地重写了getter(因为它发生在类本身中),但是如果要覆盖getProperty或setProperty,则必须在metaClass中执行此操作,而不是类本身.你所看到的行为是预料之中的.此代码演示了如何覆盖每个 class Foo { String bar } // override using setter in category @Category(Foo) class FooCategory { public String getBar() { println "in getter" } public void setBar(String bar) { println "in setter" } } use (FooCategory) { Foo foo = new Foo() foo.bar = "" foo.bar } // override using metaClass Foo.metaClass.getProperty { String pname -> println "in getProperty" } Foo.metaClass.setProperty { String pname,Object pValue -> println "in setProperty" } Foo foo = new Foo() foo.bar = "" foo.bar 输出 in setter in getter in setProperty in getProperty 并且因为getProperty / setProperty调用使得(最终)调度到getter / setter,所以可以防止getter / setter被调用,就像这样 class Foo { String bar } Foo.metaClass.getProperty { String pname -> println "in getProperty" } Foo.metaClass.setProperty { String pname,Object pValue -> println "in setProperty" } @Category(Foo) class FooCategory { String getBar() { println "in getter" } void setBar(String bar) { println "in setter" } } use (FooCategory) { Foo foo = new Foo() foo.bar = "hi foo1" foo.bar } 输出 in setProperty in getProperty (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |