【问题标题】:Wicket PropertyModel strangeness?Wicket PropertyModel 奇怪?
【发布时间】:2009-02-14 02:21:35
【问题描述】:

我是 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 替代方案?

谢谢?

【问题讨论】:

    标签: data-binding wicket


    【解决方案1】:

    PropertyModel 会做你想做的事。当查询 PropertyModel 的值时,它会在两个地方查找:

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

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

    在您的情况下,PropertyModel 构造函数中使用的属性表达式是"password",因此PropertyModel 将首先在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()));
        }
    }
    

    【讨论】:

    • 很好的答案!非常感谢您为我澄清。
    • 我一直在做的不是提供一个getter,而是希望它会调用setter。原因是我不希望用户对象有 getPassword() 方法。
    • 它仍然会调用 setter,因为您定义了一个,但是当 Wicket 呈现密码字段时,它会尝试“获取”模型值,并最终检索私有字段。如果你想防止这种情况发生,你可以重写 getObject() 以返回 null 或一串“*”字符,或者其他。
    【解决方案2】:

    迈克·斯普罗斯的回答很好! 一个小小的补充:

    在这种情况下,我不会使用属性模型。随便写

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

    并实施正确的行为,这正是您想要的。

    【讨论】:

    • +1 - 如果这是“一次性”的事情,这是获得所需功能的最简单方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    相关资源
    最近更新 更多