groovy中的get vs getProperty

groovy中的get vs getProperty,groovy,Groovy,真让我吃惊 根据groovy的文档,groovy可以使用“getProperty”方法来获取对象的属性。因此,当我想要更改获取特殊对象属性的行为时,我使用一个category类来重写“getProperty”方法。但是,它不起作用。 最后,我发现groovy框架使用category类中的“get”方法来获取属性,即使对象不是映射。 我的问题是它是一个bug还是groovy就是这样工作的 这是分类类 class DynaBeanExtension { public static void

真让我吃惊

根据groovy的文档,groovy可以使用“getProperty”方法来获取对象的属性。因此,当我想要更改获取特殊对象属性的行为时,我使用一个category类来重写“getProperty”方法。但是,它不起作用。 最后,我发现groovy框架使用category类中的“get”方法来获取属性,即使对象不是映射。 我的问题是它是一个bug还是groovy就是这样工作的

这是分类类

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, propertyName, 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, 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 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;
}
公共静态类TestSubClass{
私人最终积分e=3,f=4;
私有最终映射m=新HashMap();
公共整数getE(){
返回e;
}
公共int getF(){
返回f;
}
公共地图getM(){
返回m;
}
@凌驾
公共字符串toString(){
返回“TestSubClass{”+“e=“+e+”,f=“+f+”,m=“+m++}”;
}
}
公共静态类TestClass{
私人最终INTA=1;
私有最终TestSubClass b=新TestSubClass();
公共int getA(){
返回a;
}
公共测试子类getB(){
返回b;
}
@凌驾
公共字符串toString(){
返回“TestClass{”+“a=“+a+”,b=“+b++}”;
}
}
Map pMap=新的HashMap();
pMap.put(“b.e”、“c”);
PropertyUtilsBean pu=新的PropertyUtilsBean();
pu.setResolver(新的ExResolver(pMap));
TestClass testObj=新的TestClass();
DynaBean=新的CustomWrapDynaBean(testObj,pu);
int c=使用(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);
    }

}
公共类ExResolver实现解析器{
私有静态最终字符嵌套=';
私有静态最终字符映射_START='(';
私有静态最终字符映射_END=');
私有静态最终字符索引_START='[';
私有静态最终字符索引_END='];
专用最终分解器;
私人最终地图;
公共ExResolver(映射pMap){
这(新的DefaultResolver(),pMap);
}
公共ExResolver(解析程序解析程序,映射pMap){
this.resolver=解析器;
this.pMap=新HashMap(pMap);
}
专用字符串解析程序(字符串表达式){
对于(Map.Entry:pMap.entrySet()){
if(expression.startsWith(entry.getValue())){
字符串to=entry.getValue();
if(expression.length()==entry.getValue().length()){
return entry.getKey();
}否则{
int-toTest=expression.codePointAt(to.length());
if(toTest==嵌套的| | toTest==映射的| | | toTest==索引的|开始){
返回entry.getKey()+expression.substring(to.length(),expression.length());
}否则{
返回表达式;
}
}
}
}
返回表达式;
}
@凌驾
public int getIndex(字符串表达式){
表达式=解析表达式(表达式);
返回resolver.getIndex(表达式);
}
@凌驾
公共字符串getKey(字符串表达式){
表达式=解析表达式(表达式);
返回resolver.getKey(表达式);
}
@凌驾
公共字符串getProperty(字符串表达式){
表达式=解析表达式(表达式);
返回resolver.getProperty(表达式);
}
@凌驾
公共布尔值(字符串表达式){
表达式=解析表达式(表达式);
返回resolver.hasNested(表达式);
}
@凌驾
公共布尔值IsIndex(字符串表达式){
表达式=解析表达式(表达式);
返回解析程序.IsIndex(表达式);
}
@凌驾
公共布尔isMapped(字符串表达式){
表达式=解析表达式(表达式);
返回解析器.isMapped(表达式);
}
@凌驾
公共字符串下一步(字符串表达式){
表达式=解析表达式(表达式);
返回解析器.next(表达式);
}
@凌驾
公共字符串删除(字符串表达式){
表达式=解析表达式(表达式);
返回解析器.remove(表达式);
}
}
调用的是“get”,而不是“getProperty”


此外,在实际情况中,
DynaBeanExtension
是用groovy编译的。bean的构造是用java编译的。然后通过使用
绑定
,我将其放入测试代码中,测试代码是由java代码执行的运行时脚本。

这发生在编译本身中。让我们看一个更简单的例子

主类{
静态真空总管(def参数){
Foo Foo=新Foo()
foo.str=“”
富街
}
}
用于Groovy类

class-Foo{
字符串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);
    }
}
一个
[property]=
调用被编译成一个
ScriptBytecodeAdapter.setGroovyObjectProperty
,该调用依次调用链
MetaClassImpl.setProperty
MetaMethod.doMethodInvoke
CachedMethod.invoke
[setter]

一个
[property]
调用被编译到一个
arrayOfCallSite[1].callGroovyObjectGetProperty
,该调用反过来调用链
AbstractCallSite.callGroovyObjectGetProperty
GetEffectivePogoPropertySite.getProperty
MethodMetaProperty$GetBeanMethodMetaProperty.getProperty
MetaMethod.doMethodInvoke
java.lang.reflect.Method.invoke
[getter]/code>

用于Java类

如果使用被调用类的Java版本,如下所示

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
}
公共类Foo{
私有字符串str;
公共字符串getStr(){
返回str;
}
公共空集
in setter
in getter
in setProperty
in getProperty
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