Harshit Gupta
Harshit Gupta

Reputation: 197

Custom Annotation like Lombok

I want to implement a custom annotation which when used by other classes exposes two methods to them. Something like shown below:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface BaseEntity{
     public String toString(){ return "Hello" ;}
     public String toCustomString() { return "my hello";}
}

Now what I want is whenever any class uses the above annotation. It gets these methods exposed to it by default, something like what Lombok does when we use @Getter

@BaseEntity
public class Person{}
Person p = new Person();
p.toCustomString(); // this should work

Upvotes: 4

Views: 2315

Answers (3)

Mohammad Ayan afaq
Mohammad Ayan afaq

Reputation: 1

There is one way of you some how manage to manipulate .class file with org.ow2.asm

Upvotes: 0

Allen D. Ball
Allen D. Ball

Reputation: 2026

While not exactly what you asked, I think you can achieve what you want with a class hierarchy that takes advantage of the annotation:

@Retention(RetentionPolicy.RUNTIME)                                             
@Target(ElementType.TYPE)                                                       
public @interface BaseEntity {                                                  
    String string();                                                            
    String customString();                                                      
}                                                                               
                                                                                
public abstract class AbstractClass {                                           
    @Override                                                                   
    public String toString() {                                                  
        return getClass().getAnnotation(BaseEntity.class).string();             
    }                                                                           
                                                                                
    public String toCustomString() {                                            
        return getClass().getAnnotation(BaseEntity.class).customString();       
    }                                                                           
}

And then a concrete subclass:

@BaseEntity(string = "Hello", customString = "my hello")                        
public class Example extends AbstractClass {                                    
    public static void main(String[] args) throws Exception {                   
        Example example = new Example();                                        
                                                                                
        System.out.println(example.toString());                                 
        System.out.println(example.toCustomString());                           
    }                                                                           
}

yields:

Hello                                                                           
my hello

In response to your comment, my real-world solution is to define an annotation and an interface with default methods (which makes a toString() implementation problematic):

@BaseEntity(customString = "my hello")                                          
public class Example implements BaseEntityAnnotated {                           
    public static void main(String[] args) throws Exception {                   
        Example example = new Example();                                        
                                                                                
        System.out.println(example.toCustomString());                           
    }                                                                           
}                                                                               
                                                                                
@Retention(RetentionPolicy.RUNTIME)                                             
@Target(ElementType.TYPE)                                                       
public @interface BaseEntity {                                                  
    String customString();                                                      
}                                                                               
                                                                                
public interface BaseEntityAnnotated {                                          
    default String toCustomString() {                                           
        return this.getClass().getAnnotation(BaseEntity.class).customString();  
    }                                                                           
}

I then implement a Processor that enforces an entity annotated with BaseEntity must also implement BaseEntityAnnotated.

I have examples at AntTask, AnnotatedAntTask.getAntTaskName(), and AntTaskProcessor.

Upvotes: 2

Daly
Daly

Reputation: 879

You need to create an annotation processing class (which must be a subclass of javax.annotation.processing.AbstractProcessor) to actually add the code into the Person class.

See: http://hannesdorfmann.com/annotation-processing/annotationprocessing101

Upvotes: 1

Related Questions