2

For a project I was experimenting javassist (java binary code manipulation library).

I was able to create a simple POJO class using below code

public static Class<?> createClass(ModelClass clazz) throws NotFoundException, CannotCompileException {
    ModelProperty[] properties = clazz.getProperties();

    ClassPool classPool = ClassPool.getDefault();
    CtClass ctClass = classPool.makeClass(clazz.getName());

    // add annotation
    ClassFile classFile = ctClass.getClassFile();
    ConstPool constpool = classFile.getConstPool();
    AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
    System.out.println(Data.class.getName());
    Annotation annotation = new Annotation(lombok.Data.class.getName(), constpool);
    Annotation annotation1 = new Annotation(Component.class.getName(), constpool);
    Annotation annotation2 = new Annotation(Deprecated.class.getName(), constpool);
    annotationsAttribute.setAnnotations(new Annotation[] {annotation, annotation1, annotation2});
    ctClass.getClassFile().addAttribute(annotationsAttribute);

    for (ModelProperty property : properties) {
        String camelCaseField = property.getName().substring(0, 1).toUpperCase() + property.getName().substring(1);
        CtField ctField = new CtField(resolveCtClass(property.getType()), property.getName(), ctClass);
        ctClass.addField(ctField);

        // add getter
        // CtMethod fieldGetter = CtNewMethod.getter("get" + camelCaseField, ctField);
        // ctClass.addMethod(fieldGetter);

        // add setter
        // CtMethod fieldSetter = CtNewMethod.setter("set" + camelCaseField, ctField);
        // ctClass.addMethod(fieldSetter);
    }

    return ctClass.toClass();
}

// ModelClass
@Data
public class ModelClass {

    private String name;

    private ModelProperty[] properties;

    public void setName(String name) {
        this.name = name;
    }

    public void setModelProperty(ModelProperty[] properties) {
        this.properties = properties;
    }

}

// ModelProperty
@Data
public class ModelProperty {

    private String name;

    private Class<?> type;

    public void setType(String type) {
        switch (type.toLowerCase()) {
            case "int":
            case "integer":
                this.type = Integer.class;
                break;
            case "float":
                this.type = Float.class;
                break;
            case "str":
            case "string":
                this.type = String.class;
                break;
            case "bool":
            case "boolean":
                this.type = Boolean.class;
                break;
            default:
                this.type = String.class;
                break;
        }
    }
}

I was able to create class by using createClass method. While inspecting class with Reflection API, I've noticed that lombok.Data annotation is not adding to class.

Class<?> clazz = PojoCreator.createClass(modelClassPerson);

for (final Method method : clazz.getMethods()) {
    System.out.println(method);
}
for (final Annotation annotation : clazz.getAnnotations()) {
    System.out.println(annotation);
}
for (final Method method : clazz.getDeclaredMethods()) {
    System.out.println(method);
}
for (final Annotation annotation : clazz.getDeclaredAnnotations()) {
    System.out.println(annotation);
}

Output

public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
@org.springframework.stereotype.Component(value="")
@java.lang.Deprecated(forRemoval=false, since="")
@org.springframework.stereotype.Component(value="")
@java.lang.Deprecated(forRemoval=false, since="")

As you can see from the output spring.Component and javalang.Deprecated is added but lombok.Data didn't.

pom.xml

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <!-- <scope>annotationProcessor</scope> -->
</dependency>

Tried setting scope as compile, runtime, provided but none seems to work.

Using mvn spring-boot:run to execute in command line

Where did I go wrong?

Thanks.

0

1 Answer 1

5

TL;DR

You cannot use lombok at runtime, you need to generate your boilerplate code by yourself.

Why?

This cannot work because lombok uses an annotation processor (see this and that).

This means that lombok is run when the program. is compiled.

As you try to insert annotations at runtime, the lombok annotations will not be processed and nothing will be generated.

If you look at the javadoc of lombok annotations like @Data, you can see the following:

@Retention(SOURCE)

This means that the annotation is visible at compile-time but not it is not present in the bytecode and you also cannot access it at runtime.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your inputs. Is there any way we can modify the annotation Retention? Or any way we can invoke the method which checks for this annotation and adds getters/setters methods of Lombok. I actually tried checking the Lombok source repo but couldn't figure it out.
No you can't. Also, lombok wouldn't even care about the it at runtime if the retention was RUNTIME
@JayachandraCh this looks much like an xy problem. What you want to achieve? Generate methods like hashCode, equals, toString? Well, you are already using a code manipulation library… But you should be aware that you can’t add members to an already loaded class at runtime in general. Besides that, there wouldn’t be any point in generating getter, setters, and constructors at runtime, when there is no code actually using them, as they were absent at compile-time. Further, incomplete classes relying on Lombok wouldn’t get compiled anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.