During development of Insight plugins we sometimes come across the need to access a private member of some 3rd party library.
The common approach for this is to use reflection:
While this is a widely accepted and simple approach, we searched for a way to improve this, mainly due to performance concerns as we try to maintain a very low overhead for our code agent.
Following is an alternative way we came up with for doing this with AspectJ.
The main idea is to use a mixin aspect (using inter-type declarations) that introduces a getter for the private member to the accessed class.
Then an around advice can be written to intercept calls to this getter method, in which the private member is returned and no call to proceed() is made.
This is similar to the useful idioms described in AspectJ in Action, Second Edition (Section 5) for providing a default interface implementation or for introducing members to multiple types, with the addition of the around advice that "hijacks" calls to the new getter.
It is important to note here that while it seems that we have declared an interface that any class can implement, the implementing aspect relies on the actual instrumented object being of the concrete SomeClass type.
This means that SomeClass must be visible to your code (public). Otherwise refelction is still the only option.
The aspect is declared as privileged in order to enable the access of the private member of the target object once it has been cast into the concrete SomeClass type.
Here are the classes in play:
- The class with the private member
- The interface declaring the public getter
- The privileged aspect, containing the mixin declaration of the interface and the around advice
- Example of accessing private member from a different class
Two things should be noted when using load-time weaving:
- Since AspectJ will only weave during load time, the interface should be declared in a separate java class. This is necessary in order for the java compiler to recognize these calls from other classes : ((PrivateMessageExposer)privateClass).getPrivateMessage();
- In order to protect your code from API changes in 3rd party libraries, you should catch NoSuchMethodError exceptions that will be thrown during runtime.
Following is a summary of some basic performance tests we ran, where we compare execution times of a loop that is executed n times with reflection/weaving. The loop simply accesses the privateMessage field of the same instance n times consecutively.
The tests were run with the following hardware – 8 Cores x Intel Xeon E5410 @ 2.33 GHz. 16 GB memory (Heap 1GB).
As the table shows, the performance gain reaches 31% as the number of execution times gets higher, but there seems to be some performance degradation for lower numbers.
Depending on your needs and existing use of AspectJ, this could be a simple way to gain a performance improvement. In order to know if this will indeed result in a performance improvement and of what magnitude, you should run your own performance tests, since the results above are not conclusive, and moreover, represent a very simlified use case.
In addition to the possible performance gain, you gain more type safety than with reflection, as can be seen by this line of code : return ((SomeClass )obj).privateMessage;
– Talya Gendler, Spring Insight Engineering