0

So, lets say I have a class Person and i want to add Myntra annotation to getLastName() method at runtime (which I have accomplished using Javassist library )

But I want the changes to be permanent so that when I run it next time the annotation should be there !!

How can I do that?

package com.flipkart.aditya.annotations;


public class Person {
    private String firstName;
    private String lastName;
    private String adhaarID;
    private int employeeID;


    public Person(String firstName, String lastName, String adhaarID, int employeeID) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.adhaarID = adhaarID;
        this.employeeID = employeeID;
    }

    @Myntra
    @Jabong
    public String getFullName()
    {
        return firstName+" "+lastName;
    }


    @Xyz
    public String getFirstName()
    {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Myntra
    public String getAdhaarID() {
        return adhaarID;
    }

    @Jabong
    @Xyz
    public int getEmployeeID() {
        return employeeID;
    }
}

This is How I did it using javassist lib

package com.flipkart.aditya.annotations;


import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;

public class AddRunTimeAnnotation {
    public static void addNewAnnotationToMethod(String className,String methodName) throws Exception{

        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.getCtClass(className);
        CtMethod ctMethod = cc.getDeclaredMethod(methodName);
        ClassFile ccFile = cc.getClassFile();
        ConstPool constpool = ccFile.getConstPool();
        AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
        Annotation annot = new Annotation("com.flipkart.aditya.annotations.Myntra", constpool);
        attr.addAnnotation(annot);
        ctMethod.getMethodInfo().addAttribute(attr);
        Class<?> c =cc.toClass();



    }
}

This is my Myntra annotation

package com.flipkart.aditya.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Myntra {
}

NOTE: Jabong and xyz are also the annotation similiar to Myntra but have nothing to do with my question.

And this is how my main() functions looks like--> I am here adding a new Myntra annotation to the getLastName() method and then printing all the methods which have Myntra annotation on it using java reflection.

public class NewApplicationToTestApproachOne {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        try {
            AddRunTimeAnnotation.addNewAnnotationToMethod("com.flipkart.aditya.annotations.Person", "getLastName");
        } catch (Exception e) {

            e.printStackTrace();
        }
        Person person = new Person("Ravan", "lanka wale", "0000 0000 0000", 420);
        Class<?> reflectClass = Person.class;
        Method[] arrayOfMethods = reflectClass.getDeclaredMethods();
        for (Method method : arrayOfMethods) {
            if (method.isAnnotationPresent(Myntra.class)) {
                System.out.println(method.invoke(person, null));
            }
        }

    }

}

So its working fine at the runtime--> OUTPUT IS:

Ravan lanka wale
0000 0000 0000
lanka wale

But I want the annotation added to the getLastName() method to be permanent and for ever. I am not sure if its possible or not? If yes--> please tell me how to do it !!

Aditya Verma
  • 428
  • 6
  • 22

1 Answers1

0

Add your annotation to the method definition:

@Myntra
public String getLastName() {
    return lastName;
}

You won't need the code that dynamically adds the annotation at runtime. Just declare it and it will be compiled in. Permanently.

Thomas Timbul
  • 1,634
  • 6
  • 14
  • Umm, that is something I can always do. But I don't wanna make changes to the code for every new update. To get it done at the runtime is really the need. – Aditya Verma Feb 11 '20 at 15:21
  • So while you're writing code, you don't want to add one more line for the annotation, but instead slow down your application at runtime for dynamically adding annotations to certain methods (which you should have known about at compile time). To me that's like saying "I won't use a dishwasher, because I can't be bothered to put things in it". I'm afraid I don't understand the motive at all. – Thomas Timbul Feb 12 '20 at 11:31
  • The motive is much deeper and we already have a system like the one your suggesting and we wanna make it dynamic. – Aditya Verma Feb 12 '20 at 15:56
  • We just dont wanna use the dishwasher anymore !! – Aditya Verma Feb 12 '20 at 15:57
  • 1
    @AdityaVerma you already have code which does it at runtime. So what’s your question? – Holger Feb 12 '20 at 16:25
  • Hi @Holger, I mean is there any way I could make it permanent? – Aditya Verma Feb 12 '20 at 16:30
  • I want the changes made at the runtime to somehow be permanent and not limited to that runtime only, like I want it to appear in the code. – Aditya Verma Feb 12 '20 at 16:33
  • 1
    @AdityaVerma you should decide. “at runtime” is the opposite of “permanent”. If you are willing to insert a processing step after compiling the classes, you can use `writeFile(…)` instead of `toClass()` to produce class files for subsequent use. – Holger Feb 12 '20 at 16:34
  • Can you Please show the me a show snippet how to do it. – Aditya Verma Feb 13 '20 at 02:08
  • 1
    @AdityaVerma you already have the code. You only have to replace `Class> c =cc.toClass();` with `cc.writeFile​("path/to/directory");`. Alternatively, you can call `toBytecode()` to get a `byte[]` and use whatever I/O method you wish. Note that overwriting the existing class files you’re currently using only works if they are in the default filesystem, i.e. not in a jar or module image. – Holger Feb 13 '20 at 08:43
  • Oh Thanks a @Holger, that solves my problem !! Is there any way to overwrite an existing class files in a jar? bc eventually this whole thing I am doing gonna be used as a jar only !! – Aditya Verma Feb 13 '20 at 10:24
  • Or is there any alternative to that? – Aditya Verma Feb 13 '20 at 10:41
  • @AdityaVerma perhaps you can write the classes to a 'special' (predetermined) directory, which is first on the classpath, so anything you've written would be reloaded from there in the future. Danger might be that the user/hacker (if this isn't some internal thing) could override any functionality in the system by placing their modified classes into that same place. It seems to me that the correct place to do all this is not at 'runtime', but as part of the build process, somewhere between compile and package. – Thomas Timbul Feb 13 '20 at 11:07