使用java.bean API检查非公共类的实例
我试图使用Clojure的使用java.bean API检查非公共类的实例,java,clojure,javabeans,introspection,Java,Clojure,Javabeans,Introspection,我试图使用Clojure的(bean obj)检索与对象相关的不可变映射 在Clojure 1.4.0标准库中,实现方式大致相同(翻译成伪代码,供不熟悉Clojure的人访问): 在大多数情况下,这很好——在其默认实现中不返回非公共方法。但是,当被检查的对象是非公共类的实例时,它返回该类上的公共方法——即使在不引发IllegalArgumentException(“无法调用非公共类的公共方法”)的情况下实际上无法调用这些方法 如何解决这个问题?我正在查看文档,但是我没有看到一个明显的方法来确定一
(bean obj)
检索与对象相关的不可变映射
在Clojure 1.4.0标准库中,实现方式大致相同(翻译成伪代码,供不熟悉Clojure的人访问):
在大多数情况下,这很好——在其默认实现中不返回非公共方法。但是,当被检查的对象是非公共类的实例时,它返回该类上的公共方法——即使在不引发IllegalArgumentException
(“无法调用非公共类的公共方法”)的情况下实际上无法调用这些方法
如何解决这个问题?我正在查看文档,但是我没有看到一个明显的方法来确定一个不涉及try/catch块的类的权限。。。我觉得这不太可能是最佳实践。此外,在非公共类上的方法实现公共接口的情况下,应该有一些机制来确定可以安全地调用此方法。您可以发现类上的修饰符,因此类似这样的内容应该允许您检查对象是否是私有类的实例(未经过严格测试)
这个问题可以通过在继承树中搜索包含相同方法的公共类或接口来解决。在Clojure中,可以按如下方式实现(尽管性能较差):
(defn- public-version-of-method [^Method method]
"returns a Method built against a public interface or superclass
declaring this method, or nil if none exists"
(let [sig (method-sig method)]
(loop [current-class (. method (getDeclaringClass))
pending-supers (seq (supers current-class))]
(if (and current-class
(Modifier/isPublic (.getModifiers current-class))
(some (fn [x] (= sig (method-sig x)))
(. current-class (getDeclaredMethods))))
(. current-class (getDeclaredMethod
(.getName method)
(.getParameterTypes method)))
(if pending-supers
(recur (first pending-supers)
(next pending-supers))
nil)))))
…然后在(方法m的公共版本)
上调用.invoke
,而不是m
(如果它返回非nil值),或者如果此方法返回nil值,则接受该方法不可公开访问
(以上代码已作为建议的修补程序的一部分提交到上游)。不幸的是,在私有类实现公共接口的情况下,此答案本身不足以确定通过该接口定义的方法是否可访问。结合从PropertyDescriptor识别接口的方法,这可能就足够了。如果对象属于实现接口的类(根据定义是公共的),那么无论该类的隐私如何,您都应该能够调用接口上的方法。其他的都是bug。注意,Java在这里有很多不必要的负担,这是由于内部类被添加到语言中的方式造成的。私有类仅作为内部类才有意义。在您的示例的结构中,我可能遗漏了一些东西。我有一个非公共类,包含许多公共方法。其中一些方法可以通过实现接口的类公开调用;其中一些公共方法无法调用,因为它们不是由任何公共类或接口定义的,而是仅在非公共类本身中定义的。驱动这个的真实用例是
com.atlassian.crowd.embedded.ofbiz.OfBizUser
,来自atlassian的群组产品,用于Jira;我同意他们在非公共类上使用公共方法是没有意义的,但我唯一能控制的是提交一张罚单,提出同样的建议。顺便说一句,你是对的,我在这里的第一个评论是不准确的——问题是确定公共方法是否通过任何接口定义,或者它是否只在非公共类中定义。实际上,非公共接口是存在的。回到真实世界的jira用例,com.atlassian.crowd.embedded.ofbiz.IdName
正是如此。+1-应该不会这么难:-),作为参考,Apache commons beanutils也有类似的功能:@sw1nn感谢您指出Apache commons实现——这非常有用!
public boolean isInstanceOfPrivateClass(Object o) {
return Modifier.isPrivate(o.getClass().getModifiers());
}
(defn- public-version-of-method [^Method method]
"returns a Method built against a public interface or superclass
declaring this method, or nil if none exists"
(let [sig (method-sig method)]
(loop [current-class (. method (getDeclaringClass))
pending-supers (seq (supers current-class))]
(if (and current-class
(Modifier/isPublic (.getModifiers current-class))
(some (fn [x] (= sig (method-sig x)))
(. current-class (getDeclaredMethods))))
(. current-class (getDeclaredMethod
(.getName method)
(.getParameterTypes method)))
(if pending-supers
(recur (first pending-supers)
(next pending-supers))
nil)))))