Alors qu'il n'y a pas de moyen de passer un tableau directement sous forme d'une annotation valeur de paramètre, il est un moyen efficace d'obtenir un comportement similaire (selon la façon dont vous prévoyez d'utiliser votre annotations, cela peut ne pas fonctionner pour chaque cas d'utilisation).
Voici un exemple-disons que nous avons une classe InternetServer
et il a un hostname
de la propriété. Nous aimerions utiliser Java ordinaire de Validation pour s'assurer qu'aucun objet a une "réservés" nom d'hôte. On peut (un peu minutieusement) passer un tableau de réservé les noms d'hôtes à l'annotation qui gère la validation de nom de domaine.
mise en garde - avec Java Validation, il serait plus coutume d'utiliser la "charge utile" pour passer à ce type de données. Je voulais que cet exemple être un peu plus générique, j'ai donc utilisé une interface personnalisée de classe.
// InternetServer.java -- an example class that passes an array as an annotation value
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.Pattern;
public class InternetServer {
// These are reserved names, we don't want anyone naming their InternetServer one of these
private static final String[] RESERVED_NAMES = {
"www", "wwws", "http", "https",
};
public class ReservedHostnames implements ReservedWords {
// We return a constant here but could do a DB lookup, some calculation, or whatever
// and decide what to return at run-time when the annotation is processed.
// Beware: if this method bombs, you're going to get nasty exceptions that will
// kill any threads that try to load any code with annotations that reference this.
@Override public String[] getReservedWords() { return RESERVED_NAMES; }
}
@Pattern(regexp = "[A-Za-z0-9]{3,}", message = "error.hostname.invalid")
@NotReservedWord(reserved=ReservedHostnames.class, message="error.hostname.reserved")
@Getter @Setter private String hostname;
}
// NotReservedWord.java -- the annotation class
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy=ReservedWordValidator.class)
@Documented
public @interface NotReservedWord {
Class<? extends ReservedWords> reserved ();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "{err.reservedWord}";
}
// ReservedWords.java -- the interface referenced in the annotation class
public interface ReservedWords {
public String[] getReservedWords ();
}
// ReservedWordValidator.java -- implements the validation logic
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ReservedWordValidator implements ConstraintValidator<NotReservedWord, Object> {
private Class<? extends ReservedWords> reserved;
@Override
public void initialize(NotReservedWord constraintAnnotation) {
reserved = constraintAnnotation.reserved();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) return true;
final String[] words = getReservedWords();
for (String word : words) {
if (value.equals(word)) return false;
}
return true;
}
private Map<Class, String[]> cache = new ConcurrentHashMap<>();
private String[] getReservedWords() {
String[] words = cache.get(reserved);
if (words == null) {
try {
words = reserved.newInstance().getReservedWords();
} catch (Exception e) {
throw new IllegalStateException("Error instantiating ReservedWords class ("+reserved.getName()+"): "+e, e);
}
cache.put(reserved, words);
}
return words;
}
}