As annotations podem ter atributos que são obrigatórios ou opcionais, sendo que os opcionais a linguagem exige que se defina um valor padrão. Para deixar um atributo que não seja primitivo como opcional, nada mais óbvio do que definí-lo com “default null”, certo? Mas será que isso funciona?
O exemplo abaixo apresenta como deixamos atributos da annotation com valores padrões:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface GuardarLogAlteracao {
String value() default "";
boolean exibirValor() default true;
}
Observe que “value” possui como valor padrão uma string vazia e “exibirValor” possui “true”. Essa annotation poderia ser utilizado como o seguinte exemplo:
public class Usuario {
@GuardarLogAlteracao("Nome do usuário")
private String nome;
@GuardarLogAlteracao(value = "Senha", exibirValor = false)
private String senha;
//getters e setters...
}
Para “nome” o atributo “exibirValor” será “true”. Voltando a questão principal, se adicionarmos um atributo que seja um objeto, poderíamos definí-lo como nulo por padrão como abaixo:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface GuardarLogAlteracao {
String value() default "";
boolean exibirValor() default true;
Class<? extends FormatadorLog> formatador() default null;
}
Então utilizaríamos a annotation dessa forma, onde por padrão “formator” é nulo para “nome” e “senha”:
public class Usuario {
@GuardarLogAlteracao("Nome do usuário")
private String nome;
@GuardarLogAlteracao(value = "Senha", exibirValor = false)
private String senha;
@GuardarLogAlteracao(formatador = FormatadorData.class)
private Date dataAlteracao;
//getters e setters...
}
Aí vem o problema: isso não compila. O erro retornado pelo compilador é “The value for annotation attribute GuardarLogAlteracao.formatador must be a class literal“.
O motivo disso é que o compilador bloqueia valores nulos para os campos das annotations para evitar o uso incorreto como “
@GuardarLogAlteracao(value = null)“. Isso facilita para quem for implementar o código que tratará a annotation, pois não será necessário validar se os campos possuem valor diferente de nulo e lançar NullPointerException. Na
JSR-308 existe um texto que diz respeito a essa questão.
Para contornar essa limitação encontrei algumas pessoas que utilizaram formas altenativas (pra não chamar de “xunxo” ou “gambiarra”)
como esta:
public @interface Optional {
public String value() default NULL;
public static final NULL = "THIS IS A SPECIAL NULL VALUE" +
"- DO NOT USE";
}
Pessoalmente eu não gosto desse tipo de solução. Minha sugestão é tentar remodelar a idéia inicial, por exemplo, separando o atributo opcional em outra annotation:
public class Usuario {
@GuardarLogAlteracao("Nome do usuário")
private String nome;
@GuardarLogAlteracao(value = "Senha", exibirValor = false)
private String senha;
@GuardarLogAlteracao("Data de Alteração")
@FormatadorLog(FormatadorData.class)
private Date dataAlteracao;
//getters e setters...
}
Apesar de ser necessário mais uma annotation, essa seria uma solução mais elegante para o problema. E você, tem outra sugestão?