Using enum as annotation - java

I have an enum :
public enum Vehicle {
CAR,
BUS,
BIKE,
}
I intend to use these enum values as annotations : #Vehicle.CAR, #Vehicle.BUS, #Vehicle.BIKE. Does java allow me to define them as annotations ?

No You can not do this. But if you want to use enum in annotation you can do like this
class Person {
#Presentable({
#Restriction(type = RestrictionType.LENGTH, value = 5),
#Restriction(type = RestrictionType.FRACTION_DIGIT, value = 2)
})
public String name;
}
enum RestrictionType {
NONE, LENGTH, FRACTION_DIGIT;
}
#Retention(RetentionPolicy.RUNTIME)
#interface Restriction {
//The below fixes the compile error by changing type from String to RestrictionType
RestrictionType type() default RestrictionType.NONE;
int value() default 0;
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
#interface Presentable {
Restriction[] value();
}

You can't use enum as annotations. But you can add the enum as an element of the annotation.
The enum
public enum Priority {
LOW,
MEDIUM,
HIGH
}
The annotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface TestAnnotation {
Priority priority() default Priority.MEDIUM;
}
The annotation usage
#TestAnnotation(priority = Priority.HIGH)
public void method() {
//Do something
}

Related

How to read a default value specified in #interface

I am trying to understand why I would use #interface. I see many tutorials explaining what all those annotations mean but no where could I find in simple terms how (or why) I can use them.
As a made up example
#Target({ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface MyAnnotation {
String getAString() default "blah";
}
Suppose I use this annotation on a class.
#MyAnnotation
public class TestClass {
public String test(){
return this.getAString();
}
}
Can I call getAString() without using reflection?
If not, what can be
a possible use of it?
Here is an example on how you can use annotation fields:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MyAnnotation {
public String name();
public String value();
}
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
The example is taken from here:
http://tutorials.jenkov.com/java-reflection/annotations.html
Also see this:
#interface default declaration usage in Java

Java custom annotations takes another annotation

how can I write a custom annotation that takes another annotation and the values?
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotation{
Class<? extends TestAnnotationChild> annotation();
}
The second annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotationChild{
}
And I would like to do something like
#TestAnnotation(#TestAnnotationChild={values})
How can I do something like that?
This is how it is done.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotation {
TestAnnotationChild child();
// Or for an array
TestAnnotationChild[] children();
}
Usage
#TestAnnotation(
#TestAnnotationChild(
value = "42",
anotherValue = 42
)
)
However this part of your statement
and the values
does make me think you want to do something non-ordinary.
Could you clarify?
You should just use TestAnnotationChild value(); instead of Class<? extends TestAnnotationChild> annotation();.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotation{
TestAnnotationChild value();
}
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotationChild {
// String or whatever Object you want
String[] value();
}
Now you can use the Annotations as you wanted:
#TestAnnotation(#TestAnnotationChild({"TEST"}))
you can just have a property of type TestAnnotationChild in your TestAnnotation, just like it was a string, or whatever else

Making a Jersey bean validation annotation generic

I have a Jersey Rest API like this:
#POST
#Path("/doorder")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("text/plain")
public String doOrder(#BeanParam final #Valid OrderBean order) {
// Some implementation here
}
All my inputs are store in this bean:
#AddressAtLeastOne
public final class OrderBean {
#FormDataParam("address")
private String address;
#FormDataParam("city")
private String city;
#FormDataParam("postcode")
private String postcode;
// Other member variables
// Getters and setters
}
I added an annotation to validate the address (#AddressAtLeastOne). The address is valid if at least one of the 3 fields has a value.
Here's the annotation definition:
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
#Retention(RUNTIME)
#Constraint(validatedBy = AddressAtLeastOneValidator.class)
#Documented
public #interface AddressAtLeastOne {
String message() default "Address requires at least one field";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And here's the validator:
public class AddressAtLeastOneValidator implements ConstraintValidator<AddressAllOrNone, OrderBean> {
#Override
public boolean isValid(OrderBean demoBean, ConstraintValidatorContext constraintValidatorContext) {
// Check for at least one value
if((demoBean.getAddress() != null && !demoBean.getAddress().equals("") ||
(demoBean.getCity() != null && !demoBean.getCity().equals("")) ||
(demoBean.getPostcode() != null && !demoBean.getPostcode().equals("")))) {
return true;
}
return false;
}
}
Everything is fine! But now I want to rename the annotation #AddressAtLeastOne to #AtLeastOne and make it generic, so that I can apply it to any class. I need a mechanism where I can specify which member variables are part of the group I want to validate with #AtLeastOne. How can I do that?
One approach of doing this is to use Reflection -
Create a custom annotation suppose #GroupNotNullField and apply this annotation to all fields in bean class in which at least one field should have value. By this way, you can skip some fields in which validation is not required.
In the validator class, get all the fields of the bean class using Reflection
Check all the fields which are annotated with #GroupNotNullField annotation
Get the value of all such fields and check that at least one has value.
Return true or false depending on validation check.

Java Annotation "Inheritance"

I would like to generate tables from annotated objects. Right now I have the following schema in mind. I would like to annotate the object as follows:
#UI.App(
name = "locations",
columns = {
#UI.Presenter.PropertyColumn("title"),
#UI.Presenter.PropertyColumn("enabled"),
#UI.Presenter.StatusColumn,
#UI.Presenter.LastModifiedColumn
}
)
public class Location {
private String title;
private Boolean enabled;
}
For that I intended to use the following annotations
public interface UI {
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface App {
public String name();
public Presenter.Column[] columns() default {};
}
public interface Presenter {
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface Column {}
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface PropertyColumn {
public String value();
public boolean editable() default false;
}
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface StatusColumn {}
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface LastModifiedColumn {}
}
}
With annotation inheritance I would just let PropertyColumn, StatusColumn, and LastModifiedColumn to extend the Column interface. But there's no interface inheritance.
The main goal here is to have the overview annotation as concise as possible. What is the best way to achieve my goal?
This might be a case where annotations simply aren't flexible enough to represent complex structures. Although not as clean looking, I would consider using a single column annotation and creating enum constants for each column type like this:
#Retention(RetentionPolicy.RUNTIME) #Target({ElementType.TYPE})
public #interface Column {
ColumnType value();
String property() default "";
boolean editable() default false;
}
#UI.App(
name = "locations",
columns = {
#UI.Presenter.Column(value=ColumnType.PROPERTY, property="title"),
#UI.Presenter.Column(value=ColumnType.PROPERTY, property="enabled"),
#UI.Presenter.Column(ColumnType.STATUS),
#UI.Presenter.Column(ColumnType.LAST_MODIFIED)
}
)
Caveats are you need additional checking and documentation to prevent property and editable to be used with any column type. This approach won't work if you plan to add more column types with additional values, as it probably gets too complex then.

Is there something like Annotation Inheritance in java?

I'm exploring annotations and came to a point where some annotations seems to have a hierarchy among them.
I'm using annotations to generate code in the background for Cards. There are different Card types (thus different code and annotations) but there are certain elements that are common among them like a name.
#Target(value = {ElementType.TYPE})
public #interface Move extends Page{
String method1();
String method2();
}
And this would be the common Annotation:
#Target(value = {ElementType.TYPE})
public #interface Page{
String method3();
}
In the example above I would expect Move to inherit method3 but I get a warning saying that extends is not valid with annotations. I was trying to have an Annotation extends a common base one but that doesn't work. Is that even possible or is just a design issue?
You can annotate your annotation with a base annotation instead of inheritance. This is used in Spring framework.
To give an example
#Target(value = {ElementType.ANNOTATION_TYPE})
public #interface Vehicle {
}
#Target(value = {ElementType.TYPE})
#Vehicle
public #interface Car {
}
#Car
class Foo {
}
You can then check if a class is annotated with Vehicle using Spring's AnnotationUtils:
Vehicle vehicleAnnotation = AnnotationUtils.findAnnotation (Foo.class, Vehicle.class);
boolean isAnnotated = vehicleAnnotation != null;
This method is implemented as:
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
return findAnnotation(clazz, annotationType, new HashSet<Annotation>());
}
#SuppressWarnings("unchecked")
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
try {
Annotation[] anns = clazz.getDeclaredAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType() == annotationType) {
return (A) ann;
}
}
for (Annotation ann : anns) {
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
if (annotation != null) {
return annotation;
}
}
}
}
catch (Exception ex) {
handleIntrospectionFailure(clazz, ex);
return null;
}
for (Class<?> ifc : clazz.getInterfaces()) {
A annotation = findAnnotation(ifc, annotationType, visited);
if (annotation != null) {
return annotation;
}
}
Class<?> superclass = clazz.getSuperclass();
if (superclass == null || Object.class == superclass) {
return null;
}
return findAnnotation(superclass, annotationType, visited);
}
AnnotationUtils also contains additional methods for searching for annotations on methods and other annotated elements. The Spring class is also powerful enough to search through bridged methods, proxies, and other corner-cases, particularly those encountered in Spring.
Unfortunately, no. Apparently it has something to do with programs that read the annotations on a class without loading them all the way. See Why is it not possible to extend annotations in Java?
However, types do inherit the annotations of their superclass if those annotations are #Inherited.
Also, unless you need those methods to interact, you could just stack the annotations on your class:
#Move
#Page
public class myAwesomeClass {}
Is there some reason that wouldn't work for you?
In addition to Grygoriys answer of annotating annotations.
You can check e.g. methods for containing a #Qualifier annotation (or an annotation annotated with #Qualifier) by this loop:
for (Annotation a : method.getAnnotations()) {
if (a.annotationType().isAnnotationPresent(Qualifier.class)) {
System.out.println("found #Qualifier annotation");//found annotation having Qualifier annotation itself
}
}
What you're basically doing, is to get all annotations present on the method and of those annotations you get their types and check those types if they're annotated with #Qualifier. Your annotation needs to be Target.Annotation_type enabled as well to get this working.
Check out https://github.com/blindpirate/annotation-magic , which is a library I developed when I had the same question.
#interface Animal {
boolean fluffy() default false;
String name() default "";
}
#Extends(Animal.class)
#Animal(fluffy = true)
#interface Pet {
String name();
}
#Extends(Pet.class)
#interface Cat {
#AliasFor("name")
String value();
}
#Extends(Pet.class)
#interface Dog {
String name();
}
#interface Rat {
#AliasFor(target = Animal.class, value = "name")
String value();
}
#Cat("Tom")
class MyClass {
#Dog(name = "Spike")
#Rat("Jerry")
public void foo() {
}
}
Pet petAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Pet.class);
assertEquals("Tom", petAnnotation.name());
assertTrue(AnnotationMagic.instanceOf(petAnnotation, Animal.class));
Animal animalAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Animal.class);
assertTrue(animalAnnotation.fluffy());
Method fooMethod = MyClass.class.getMethod("foo");
List<Animal> animalAnnotations = AnnotationMagic.getAnnotationsOnMethod(fooMethod, Animal.class);
assertEquals(Arrays.asList("Spike", "Jerry"), animalAnnotations.stream().map(Animal::name).collect(toList()));

Categories

Resources