JavaBeans 和内省 - 布尔值和索引属性搞砸了?
我的一位前同事半小时前开始讨论 JavaBeans,以及为什么它们在 JSF 中没有按照他想要的方式工作。特殊情况是关于布尔属性的。
1。对于名为 isUrl
的布尔属性,Eclipse 会生成此属性
private boolean isUrl;
public boolean isUrl() {..}
public boolean setUrl(boolean url) {..}
,但这在 JSF 中不起作用。他通过添加 public boolean getIsUrl() 使其工作。实现可能有错误,所以让我们通过使用内省 API 来确定谁是对的。:
BeanInfo info = Introspector.getBeanInfo(ClassTest.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
System.out.println(pd.getName() + ": " + pd.getReadMethod() +
" : " + pd.getWriteMethod());
}
对于上面的代码,这会打印两种方法 - 即 Eclipse是对的,JSF 是错的。但这对我来说听起来很可疑,因为规范并没有不要提及任何有关双“是”的事情。
但是在查看规范时,我看到了一些我从未使用过的东西 - 所谓的索引属性。您可以先使用private String[] bar
,然后再使用public String getBar(int idx)
。所以:
2。我用 Introspector
尝试过,但它没有找到 bar 的读取方法。上述代码的结果是:bar: null : null
。所以我开始思考 - 现在内省器不遵循规范。也许它没有遵循前一个案例,但最终,JSF 是对的。事实上,索引属性可以使给定属性有两种读取方法。对于内省 API 的 PropertyDescriptor
类来说,这是不可能的。
这会给我们带来什么——我们有一个可能损坏的 API,不符合规范。这导致了该规范的其他实现(JSF 显然使用了自定义的实现)。这会导致进一步的误解和混乱。
一个让我困扰的事情的旁注 - 在 JavaBeans 规范中,他们将方法的命名约定称为“设计模式”。这对我来说听起来不对。
那么,现在讨论问题:
- JavaBeans 规范是否明确,
- 内省 API 是否正确,
- 是否需要新的 JavaBeans 规范,至少要澄清布尔值(在一定程度上是主观的)更新的行为
。看起来 JSF 用法是 bean.isUrl
而不是 bean.url
。不使用 isUrl() 访问器是完全合理的。
PS JDK 1.6.0_20、JSF 1.2、MyFaces
A former colleague of mine started a discussion half an hour ago about JavaBeans, and why they didn't quite work the way he wants in JSF. The particular case is about boolean properties.
1. For a boolean property named isUrl
Eclipse generates this
private boolean isUrl;
public boolean isUrl() {..}
public boolean setUrl(boolean url) {..}
But this does not work in JSF. He made it work by adding public boolean getIsUrl()
The implementation might be buggy, so let's make sure who's right, by using the introspection API.:
BeanInfo info = Introspector.getBeanInfo(ClassTest.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
System.out.println(pd.getName() + ": " + pd.getReadMethod() +
" : " + pd.getWriteMethod());
}
For the above code, this prints both methods - i.e. Eclipse is right, JSF is wrong. But that sounded suspicious to me, since the specification doesn't mention anything about the double "is".
But while looking through the spec, I saw something I've never used - the so called indexed properties. You can have private String[] bar
and then public String getBar(int idx)
. So:
2. I tried that with the Introspector
, and it didn't find a read method for bar. The result from the above code was: bar: null : null
. So I came to think - now the introspector does not follow the spec. Perhaps it didn't follow it in the previous case, and ultimately, JSF is right. In fact, indexed properties can make so that there are two read methods for a given property. And that's not possible with the PropertyDescriptor
class of the introspection API.
What does this lead us to - we have a possibly broken API that does not conform to the spec. Which leads to other implementations of the spec (JSF uses a custom one obviously). Which leads to further misunderstandings and confusions.
A sidenote for something that bothered me - in the JavaBeans spec they call the naming conventions for the methods "design patterns". This sounds wrong to me.
So, now onto the questions:
- is the JavaBeans spec clear
- is the introspection API correct
- is a new JavaBeans specification needed, at least to clarify the behaviour of booleans (that's subjective to an extent)
Update. it appears the JSF usage is bean.isUrl
rathern than bean.url
. Which makes perfects sense not to work with isUrl()
accessor.
P.S. JDK 1.6.0_20, JSF 1.2, MyFaces
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(2)
正如 @Peter Lawrey 所提到的,该字段的名称与 JavaBeans 无关。它甚至不需要存在,或者您可以给它一个愚蠢的名称,例如添加 m_
前缀。
您没有为整个 bar
属性提供合适的读取或写入方法,因此这些方法不会显示。您无法在运行时将 Method
合成到现有类。我相信索引属性是较晚的版本,即使没有明显的 @since
,因此它们不被 java.beans
接口使用。
我没有 JSF 规范(它位于 jcp.org 律师墙后面),所以不知道它声称什么。它可能会指定与 JavaBeans 规范不同的内容[可能],或者您可能正在使用带有错误的实现[我猜也有可能]。
“设计模式”只是一个短语。就像我们设计中出现的模式一样。它不是 GoF 中的设计模式。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
Java Bean 属性由方法定义,而不是由字段定义。因此
PropertyDescriptor
< /a> 类有getReadMethod()
和getWriteMethod()
方法,但没有getField()
方法。就我个人而言,我认为你的同事正在使用一种不好的做法。
a)
is
是动词。字段不应以动词命名。b) 虽然不是必需的,但好的做法是将字段命名为属性,这样您就可以编写如下代码:
虽然此代码未标准化,但它遵循约定并且非常方便。如果您不遵循这样的约定,则无法将字段与属性关联起来(我知道这是故意的)。
例如,我使用上面的代码来检查字段是否有注释
关于索引属性:
您可以在数组或列表(或映射)属性上使用索引语法,但前提是它们被定义为标准 bean 属性。
因此,如果您有这样的属性:
或这样:
您可以使用表达式
${bar[0]}
访问第一个成员并且使用这样的映射属性:
您可以访问映射的值到
“baz”
,就像这样${bar['baz']}
。此功能建立在标准 bean 功能之上,因此它需要常规的 getter/setter。
Java Bean Properties are defined by methods, not by fields. For this reason the
PropertyDescriptor
class hasgetReadMethod()
andgetWriteMethod()
methods, but nogetField()
methods.Personally, I think your colleague is using a bad practice.
a)
is
is a verb. Fields should not be named after verbs.b) while it's not required, good practice is to name the field like the property, which lets you write code like this:
While this code is not standardized, it is following conventions and can come in very handy. If you don't follow conventions like this, you have no way of associating a field with a property (which is intentional, I know).
e.g. I use code like the above to check if the field has annotations
About indexed properties:
You can use the index syntax on array or list (or map) properties, but only if they are defined as standard bean properties.
So if you have a property like this:
or like this:
you can access the first member with the expression
${bar[0]}
And with a map property like this:
You can access the value mapped to
"baz"
like this${bar['baz']}
.This functionality builds on top of standard beans functionality, so it requires regular getters / setters.