Wicket PropertyModel 奇怪吗?

发布于 2024-07-13 19:52:07 字数 464 浏览 7 评论 0原文

我是 Wicket 新手,正在尝试以下配置:

class User {
   private String password;

   ...

   public void setPassword(String password) {
     this.password = MD5.encode(password);
   }
   ...
}

尝试使用以下内容绑定到密码并发现 PropertyModel 的默认实现默认绑定到字段,而不是属性(奇怪的名称是吗? )

add(new PasswordTextField("password", new PropertyModel(user, "password"));

他们到底为什么要这样实施? 是否有默认使用 getter 和 setter 的 PropertyModel 替代方案?

谢谢你?

I'm new to Wicket and was trying the following configuration:

class User {
   private String password;

   ...

   public void setPassword(String password) {
     this.password = MD5.encode(password);
   }
   ...
}

After trying to use the following to bind to the password and finding out that the default implementation of PropertyModel is by default to bound to the field, not the property (weird name eh?)

add(new PasswordTextField("password", new PropertyModel(user, "password"));

Why in the world would they have implemented it this way? And is there a PropertyModel alternative that uses getter and setters by default?

Thank you?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

策马西风 2024-07-20 19:52:07

PropertyModel 已经可以完成您想要的操作。 当查询 PropertyModel 的值时,它会在两个位置查找:

  • 如果给定属性存在“getter”方法,PropertyModel 会调用该 getter检索属性的值。 具体来说,PropertyModel 查找名为 get 的方法,其中 是传递给 的属性表达式PropertyModel 构造函数,并使用反射调用该方法(如果存在)。

  • 如果不存在“getter”方法,PropertyModel 直接返回属性字段的值。 具体来说,PropertyModel 使用反射查找与传递给 PropertyModel 构造函数的属性表达式相匹配的字段。 如果找到匹配的字段,PropertyModel 将返回该字段的值。 请注意,除了公共字段之外,PropertyModel 还会检查私有字段和受保护字段是否匹配。

在您的情况下,PropertyModel 构造函数中使用的属性表达式是 "password",因此 PropertyModel 将首先在 PropertyModel 上查找方法code>user 对象称为 getPassword。 如果不存在这样的方法,PropertyModel 将返回私有password 字段的值。

由于在您的情况下,PropertyModel 返回私有字段的值而不是调用“getter”,因此您很可能在 User 类中错误地输入了 getter 的名称。 例如,如果您不小心输入了 getPasssword (包含 3 个 s),则 PropertyModel 将找不到它,并且会回退到返回私有字段。


编辑

如果您不喜欢PropertyModel的默认行为,您可以创建PropertyModel的子类,这将阻止Wicket尝试读取/写入私有字段。 这样,您可以强制通过 getter 和 setter 进行所有属性访问。

我编写了一个示例 BeanPropertyModel 类来演示这一点:

import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.model.PropertyModel;

/**
 * A custom implementation of {@link org.apache.wicket.model.PropertyModel}
 * that can only be bound to properties that have a public getter or setter method.
 * 
 * @author mspross
 *
 */
public class BeanPropertyModel extends PropertyModel {

    public BeanPropertyModel(Object modelObject, String expression) {
        super(modelObject, expression);
    }

    @Override
    public Object getObject() {
        if(getPropertyGetter() == null)
            fail("Missing getter");
        return super.getObject();               
    }

    @Override
    public void setObject(Object modelObject) {
        if(getPropertySetter() == null)
            fail("Missing setter");
        super.setObject(modelObject);
    }

    private void fail(String message) {

        throw new WicketRuntimeException(
                String.format("%s. Property expression: '%s', class: '%s'.",
                        message,
                        getPropertyExpression(),
                        getTarget().getClass().getCanonicalName()));
    }
}

PropertyModel will do what you want already. When a PropertyModel is queried for its value, it looks in two places:

  • If a "getter" method exists for the given property, the PropertyModel calls the getter to retrieve the property's value. Specifically, the PropertyModel looks for a method named get<Property>, where <Property> is the property expression passed to the PropertyModel constructor, and calls the method using reflection if it exists.

  • If no "getter" method exists, the PropertyModel returns the value of the property field directly. Specifically, the PropertyModel uses reflection find a field that matches the property expression passed to the PropertyModel constructor. If a matching field is found, the PropertyModel returns the field's value. Note that the PropertyModel will check private and protected fields in addition to public fields for a match.

In your case, the property expression used in the PropertyModel constructor is "password", so the PropertyModel will first look for a method on the user object called getPassword. If no such method exists, the PropertyModel will return the value of the private password field instead.

Since in your case the PropertyModel is returning the private field's value instead of calling the "getter", you most likely mistyped the name of the getter in your User class. For example, f you accidentally typed getPasssword (with 3 s's), the PropertyModel won't find it, and will fallback to returning the private field.


EDIT

If you don't like PropertyModel's default behavior, you can create a subclass of PropertyModel that will prevent Wicket from trying to read/write to private fields. This way, you can force all property accesses to occur through getters and setters.

I wrote an example BeanPropertyModel class to demonstrate this:

import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.model.PropertyModel;

/**
 * A custom implementation of {@link org.apache.wicket.model.PropertyModel}
 * that can only be bound to properties that have a public getter or setter method.
 * 
 * @author mspross
 *
 */
public class BeanPropertyModel extends PropertyModel {

    public BeanPropertyModel(Object modelObject, String expression) {
        super(modelObject, expression);
    }

    @Override
    public Object getObject() {
        if(getPropertyGetter() == null)
            fail("Missing getter");
        return super.getObject();               
    }

    @Override
    public void setObject(Object modelObject) {
        if(getPropertySetter() == null)
            fail("Missing setter");
        super.setObject(modelObject);
    }

    private void fail(String message) {

        throw new WicketRuntimeException(
                String.format("%s. Property expression: '%s', class: '%s'.",
                        message,
                        getPropertyExpression(),
                        getTarget().getClass().getCanonicalName()));
    }
}
权谋诡计 2024-07-20 19:52:07

迈克·斯普洛斯的回答很好!
不过,还有一点补充:

在这种情况下我不会使用属性模型。 只需编写

 new Model<String>(){ getObject(){...} setObject(){...}}

并实现正确的行为即可,这正是您想要的。

great answer by mike spross!
one small addition though:

i'd not use property model in this case. just write

 new Model<String>(){ getObject(){...} setObject(){...}}

and implement the correct bahavior, which does exactly what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文