Wicket PropertyModel estranheza?
-
23-08-2019 - |
Pergunta
Eu sou novo para Wicket e estava tentando a seguinte configuração:
class User {
private String password;
...
public void setPassword(String password) {
this.password = MD5.encode(password);
}
...
}
Depois de tentar usar o seguinte para vincular à senha e descobrir que a implementação padrão de PropertyModel é por padrão para ligado para o campo, não a propriedade (nome estranho eh?)
add(new PasswordTextField("password", new PropertyModel(user, "password"));
Por que no mundo que eles têm implementado desta maneira? E há uma alternativa PropertyModel que usos getter e setters por padrão?
Obrigado?
Solução
PropertyModel
vai fazer o que você já quer. Quando um PropertyModel
é consultado para o seu valor, ele parece estar em dois lugares:
-
Se existe um método "getter" para a propriedade dada, o
PropertyModel
chama o getter para recuperar o valor da propriedade. Especificamente, os olharesPropertyModel
para umget<Property>
método chamado, onde<Property>
é a expressão de propriedade passado para o construtorPropertyModel
, e chama o método usando a reflexão se ela existir. -
Se nenhum método "getter" existe, o
PropertyModel
retorna o valor do campo de propriedade diretamente. Especificamente, o usoPropertyModel
reflexão encontrar um campo que corresponde à expressão de propriedade passado para o construtorPropertyModel
. Se um campo correspondente for encontrado, oPropertyModel
retorna o valor do campo. Note que oPropertyModel
irá verificar campos particulares e protegidas, além de campos públicos para uma partida.
No seu caso, a expressão de propriedade usada no construtor PropertyModel
é "password"
, de modo que o PropertyModel
procurará primeiro por um método no objeto user
chamado getPassword
. Se nenhum método existe, o PropertyModel
irá retornar o valor do campo password
privada em vez.
Uma vez que no seu caso o PropertyModel
está retornando o valor do campo privada em vez de chamar o "getter", você provavelmente digitado incorretamente o nome do getter em sua classe User
. Por exemplo, f você digitou acidentalmente getPasssword
(com 3 s de), o PropertyModel
não vai encontrá-lo, e irá fallback para devolver o campo privado.
Editar
Se você não gosta o comportamento padrão do PropertyModel
, você pode criar uma subclasse de PropertyModel
que vai impedir Wicket de tentar ler / escrever para campos particulares. Dessa forma, você pode forçar todos os acessos de propriedade para ocorrer através de getters e setters.
Eu escrevi uma classe exemplo BeanPropertyModel
para demonstrar isto:
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()));
}
}
Outras dicas
grande resposta por Mike Spross! um pequeno acréscimo no entanto:
Eu não usaria modelo de propriedade neste caso. Basta escrever
new Model<String>(){ getObject(){...} setObject(){...}}
e implementar o bahavior correta, que faz exatamente o que você quer.