Search code examples
javaspringspring-bootspring-data-jpacglib

Spring CGLIB, transactions and private final field initialization


I have the following class hierarchy in my Spring Boot application:

public abstract class A {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public void method1(Object object) {
        this.objectMapper.writeValueAsString(object);
    }

}

@Component
public class B extends A {

    public void method2() {
        method1();
    }

}

in such case everything is working fine.

But when I add @Transactional(rollbackFor = Exception.class) annotation to method2() declaration, like for example:

public abstract class A {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public void method1() {
        this.objectMapper; // always NULL
    }

}

@Component
public class B extends A {

    @Transactional(rollbackFor = Exception.class)
    public void method2() {
        method1();
    }

}

and execute method2() it fails with NullPointerException in method1() because of this.objectMapper is NULL;

How to let Spring correctly initialize the private final ObjectMapper objectMapper even in case of @Transactional(rollbackFor = Exception.class) is added?

Also, in case of @Transactional annotation the class of this is B$$EnhancerBySpringCGLIB and without annotation is just plain B. So, looks like CGLIB unable to properly initialize private final ObjectMapper objectMapper.. Is there any workarounds how it can be solved?


Solution

  • Remove the final in your code. You are using @Transactional with CGLIB. How CGLIB works is it creates a proxy by extending your class. Since the below method is final it cannot extend it, since final classes cannot be extended.

    @Transactional(rollbackFor = Exception.class)
    
    public final void method2() {
        method1();
    }