Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning an @Annotation enum a value

I created

enum Restrictions{
  none,
  enumeration,
  fractionDigits,
  length,
  maxExclusive,
  maxInclusive,
  maxLength,
  minExclusive,
  minInclusive,
  minLength,
  pattern,
  totalDigits,
  whiteSpace;

  public Restrictions setValue(int value){
    this.value = value;
    return this;
  }
  public int value;
}

So that I could happily do something like this, which is perfectly legal syntax.

Restrictions r1 =
  Restrictions.maxLength.setValue(64);

The reason being is, I am using enum to restrict the type of restriction that could be used, and be able to assign a value to that restriction.

However, my actual motivation is to use that restriction in an @annotation.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Presentable {
  Restrictions[] restrictions() default Restrictions.none;
}

So that, I intended to do this:

@Presentable(restrictions=Restrictions.maxLength.setValue(64))
public String userName;

to which, the compiler croaks

The value for annotation enum attribute must be an enum constant expression.

Is there a way to accomplish what I wish to accomplish

like image 248
Blessed Geek Avatar asked Jun 10 '10 00:06

Blessed Geek


People also ask

Can you assign values to enums?

You can assign different values to enum member. A change in the default value of an enum member will automatically assign incremental values to the other members sequentially.

How do you add value to an enum?

You can add a new value to a column of data type enum using ALTER MODIFY command. If you want the existing value of enum, then you need to manually write the existing enum value at the time of adding a new value to column of data type enum.

Can enum be used as variable value?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.

Can we use Lombok for enum?

You can define the inner Fields enum/class yourself, in which case lombok will add all the enum constants / public static final fields you haven't written yourself.


3 Answers

You can do it like this:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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();
}
like image 176
Abhinav Sarkar Avatar answered Oct 08 '22 23:10

Abhinav Sarkar


A part from compilation error, suppose you are able to do exactly this. Then don't you think applying the similar annotation on some other field will ruin the first one?

I mean to say,

@Presentable(restrictions=Restrictions.maxLength.setValue(64))
public String userName;
@Presentable(restrictions=Restrictions.maxLength.setValue(32))
public String password;

The same instance will now have a different value, that is 32. So, the 64 will be lost, I believe. In case, they are processed on runtime sequentially, and at the time we change the value to 32, 64 one has already been processed. Then I suppose, we can change the setter method in the example given by mdma to something like below.

 static public Restriction setValue(int value) {    
      this.value = value;
      return this;
  }
like image 33
Adeel Ansari Avatar answered Oct 09 '22 01:10

Adeel Ansari


You can achieve what you want, but not with enums directly.

If you make Restriction a regular class, with private constructor and static constant fields, you can then use method chaining to create new instances fluently:

enum RestrictionType
{
   none,
   enumeration,
   maximumLength, 
   // ... etc.
}

class Restriction {
  static public final Restriction none = new Restriction(RestrictionType.none);
  static public final Restriction enumeration = new Restriction(RestrictionType.enumeration);
  static public final Restriction maximumLength = new Restriction(RestrictionType.maximumLength);

  ... etc

  RestrictionType type;
  int value;

  private Restriction(RestrictionType type)
  {
    this(type, 0);
  }
  private Restriction(RestrictionType type, int value)
  {
     this.type = type;
     this.value = value; // you don't really need
  }

  static public Restriction setValue(int value)
  {
      return new Restriction(type, value);
  }
}

Which is then used exactly as your original code:

@Presentable(restrictions=Restrictions.maxLength.setValue(64))
public String userName;

However, I'm concerned for the lack of OO here - if the restrictions have different behaviour or data needed for definition, then you will end up lumping everything in the Restrictions class. It will be better to create subclasses for the different restriction types.

like image 2
mdma Avatar answered Oct 09 '22 00:10

mdma