如果我有以下代码:
class Person {
String getName() {
"John Doe"
}
boolean isMan() {
true
}
}
println new Person().properties
然后,它打印:
[class:class Person, man:true, name:John Doe]
如何防止groovy基于访问器方法创建属性(人,名字)?我理解为什么groovy会创建属性,但是希望有一种方法(例如使用一些注释)来防止groovy这样做。
答案 0 :(得分:0)
您必须注意,new Person().properties
不会返回有关类字段的类属性列表,而是返回元类属性。 Groovy使用称为MetaBeanProperty
的类来表示-类字段和访问器方法。如果编译Groovy类,您将获得.class
文件,该文件将反编译为如下所示:
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class Person implements GroovyObject {
public Person() {
CallSite[] var1 = $getCallSiteArray();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
public String getName() {
CallSite[] var1 = $getCallSiteArray();
return "John Doe";
}
public boolean isMan() {
CallSite[] var1 = $getCallSiteArray();
return true;
}
}
如您所见,没有为您的getter方法创建任何文件,但是由于new Person().properties
,name
返回了man
和MetaBeanProperty
属性。
如果仅想获取类字段的映射,则必须过滤new Person().properties
返回的映射。 MetaBeanProperty
类具有此方法getField()
,只要给定的MetaBeanProperty
由类字段表示,则返回CachedField
,否则返回null
。考虑以下示例:
import groovy.transform.CompileStatic
import groovy.transform.TypeChecked
@CompileStatic
@TypeChecked
class Person {
String email
String getName() {
"John Doe"
}
boolean isMan() {
true
}
static void main(String[] args) {
def person = new Person()
def fields = person.properties.findAll {
(person.hasProperty(it.key.toString()) instanceof MetaBeanProperty) && ((MetaBeanProperty) person.hasProperty(it.key.toString())).getField() != null
}
println fields
}
}
在此示例中,我们添加了字段email
。根据上述规则过滤属性列表,将返回以下映射:
[email:null]
最后但并非最不重要的一点-这是反编译Person
文件后经过修改的.class
类的样子:
import Person._main_closure1;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.lang.Reference;
import java.util.Map;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
public class Person implements GroovyObject {
private String email;
public Person() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public String getName() {
return "John Doe";
}
public boolean isMan() {
return true;
}
public static void main(String... args) {
Reference person = new Reference(new Person());
Map fields = DefaultGroovyMethods.findAll(DefaultGroovyMethods.getProperties((Person)person.get()), new _main_closure1(Person.class, Person.class, person));
DefaultGroovyMethods.println(Person.class, fields);
Object var10000 = null;
}
public String getEmail() {
return this.email;
}
public void setEmail(String var1) {
this.email = var1;
}
}
同样,getName()
和isMan()
方法不会创建类字段,具有默认Groovy范围的email
字段会转换为具有访问器方法的私有类字段。希望对您有所帮助。
如果要查看和/或调试创建new Person().properties
地图的位置,请查看MetaClassImpl.getProperties()
method in line 2083。这是您的类调用以从元类获取属性列表的方法。如您所见,它接受两种类型的属性-缓存的字段(真实类字段)和meta bean属性(可能由字段或访问器方法表示的属性)。不幸的是,没有选项可以排除从getProperties()
方法中获取getter方法。
如果您打算将访问器方法从new Person().properties
中排除,则实现此目的的唯一方法是重命名该方法,这样它就不会被视为访问器方法(例如getName()
-> {{ 1}})。在这种情况下,Groovy的元类将不会检索此类方法的meta bean属性,并且它返回的值将不会出现在name()
映射中。