Weird NullPointerException when accessing the final field

I am not sure how to start this. I have a funny NullPointerException in the place where this should not be. I do not expect much of the answers, as the situation looks like an anomaly, but the question and answer (if I finally find it) can be useful for educational purposes. If this does not happen, I will probably delete the question.

 Caused by: java.lang.NullPointerException at com.ah.dao.hbase.Snapshotable.lock(Snapshotable.java:17) at com.ah.pipeline.dump.DumpController.dump(DumpController.java:78) 

 07: public abstract class Snapshotable { 08: private final AtomicBoolean readonly = new AtomicBoolean(false); 09: 10: abstract public TableSuit getTableInfo(); 11: 12: public boolean locked() { 13: return readonly.get(); 14: } 15: 16: public final void lock() { 17: readonly.set(true); <-- happens here 18: } 19: 20: public final void release() { 21: readonly.set(false); 22: } 23: } 

At first, the readonly variable was not final, so although it may be the effect of an unsafe publication, now I have no ideas. There are no reflective tricks with these variables in our code, but some methods of the descendants of this class are proxied using aspectj.


Update using additional information
 @Service public class HDao extends Snapshotable { @PerformanceMonitoring public void save(PatchEvent patchEvent) { if (locked()) { throw new DumpException(tableName); } @Aspect @Component public class PMAdvice { @Around(value = "@annotation(performanceMonitoring)", argNames = "jp, p") public Object saveEvent(ProceedingJoinPoint jp, PerformanceMonitoring p) throws Throwable { // basic stuff 
+5
source share
1 answer

I could reproduce this with a small program. The problem really was related to AOP. With debugging, I found that the final methods do not work with AspectJ proximation.

It turned out that proxying in AspectJ is performed by a subclass of runtime. Therefore, it creates a subclass of the shell that delegates all methods to proxy objects. It works great for non-final methods.

simplified example:

 class WrapperProxy extends MyClass { private MyClass delegate = new MyClass(); @Override public void run() { delegate.run(); } } 

This method has problems with final methods because they cannot be overridden in subclasses. AspectJ handles it in a strange way: it creates another instance of the MyClass delegate and redirects all calls to the final method to it. This delegate is not even initialized, and in my case it had zero trailing fields.

To fix my specific problem, I simply deleted the last keyword from the methods.

+1
source

All Articles