In Java, how do we protect access of lazy fields? - java

If a Java class has a field that is initialized lazily or on demand, how can we ensure that access to the lazy field is via it's initializing access method?
By way of context, we recently had a situation in which a developer added access to an object that was initialized lazily, but not via its initializing access method. This wasn't caught at compilation or in unit tests, but then caused runtime errors.
For example - in the following SSCCE, _lazyObject is initialized via the getLazyObject() method. However, if there are other methods (in the class, because it already has a private access modifier) that would want to use _lazyObject, we should access via the getLazyObject() method, as otherwise it may not have been initialized.
public class MyObject {
private transient volatile Object _lazyObject;
public Object getLazyObject() {
if (_lazyObject == null) {
synchronized (this) {
if (_lazyObject == null) {
_lazyObject = new Object();
}
}
}
return _lazyObject;
}
public void doSomething() {
Object a = _lazyObject; // may be null - will compile, but may cause runtime errors!
Object b = getLazyObject(); // subject to exceptions, will not be null - this is how it should be accessed.
// do something...
}
}
How can we ensure that the access of _lazyObject is via getLazyObject()?
Is this possible in the code within MyObject?
Alternatively, is it possible to ensure this via unit tests?

Ok, so I'm open to further suggestions, but this is the best solution that I have come up with so far.
We can 'protect' the lazy variable in an initializing object - I thought about writing this myself, but found that there are good implementations of this in Apache Commons Lang (LazyInitializer) and Google Guava (Supplier). (Credit to Kenston Choi's answer to this question.)
For example - to clarify, I've changed the lazy object class from Object to a placeholder T:
public class MyObject {
private transient Supplier<T> _lazyObject = Suppliers.memoize(new Supplier<T>() {
#Override
public T get() {
return ...; // make T
}
});
public T getLazyObject() {
return _lazyObject.get();
}
public void doSomething() {
Supplier<T> a = _lazyObject; // a is actually the Supplier
// ... but we can access either via the method
T b = getLazyObject();
// or the Supplier:
T c = _lazyObject.get();
// do something...
}
}
However, as per the comments above - one of my main use cases is serializing/de-serializing objects containing lazy fields across JVMs. In this case, after de-serialization, the Supplier will be null. As such, we need to initialize the Supplier after deserialization.
For example, using the most simple approach:
public class MyObject {
private transient Supplier<T> _lazyObject = makeSupplier();
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
_lazyObject = makeSupplier();
}
private Supplier<T> makeSupplier() {
return Suppliers.memoize(new Supplier<T>() {
#Override
public Tget() {
return ...; // make T
}
});
}
}

Related

Call method of unknown object

I have two ArrayLists - ArrayList1 and ArrayList2. Each of them is filled with objects - Object1 and Object2, respectively.
Both of these objects have method 'getText'.
Object1:
public String getText() { return "1";}
Object2:
public String getText() { return "2";}
At certain point I would like to loop through each of these lists using the same method (just with different parameter).
loopThroughList(1)
loopThroughList(2)
What is the syntax if I want to call a method, but I don't know which object it is going to be? This is the code I have so far:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getText());
}
It says Cannot resolve method getText. I googled around and found another solution:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
But this gives me NoSuchMethodException error. Even though the 'getText' method is public.
EDIT: To get the correct list, I am calling the method 'getList' of a different object (lists) that returns either ArrayList1 or ArrayList2 (depending on the provided parameter).
class Lists
public getList(list) {
if (list == 1) {
return ArrayList1;
}
else if (list == 2) {
return ArrayList2;
}
}
Define an interface for the getText method
public interface YourInterface {
String getText();
}
Implement the interface on the respective classes
public class Object1 implements YourInterface {
#Override
public String getText() {
return "1";
}
}
public class Object2 implements YourInterface {
#Override
public String getText() {
return "2";
}
}
Modify your getList method to return List<YourInterface>
public static List<YourInterface> getList(int list){
List<YourInterface> result = new ArrayList<>();
if(list == 1){
// your initial type
List<Object1> firstList = new ArrayList<>();
result.addAll(firstList);
} else {
// your initial type
List<Object2> secondList = new ArrayList<>();
result.addAll(secondList);
}
return result;
}
Declaration for loopThroughList
public static void loopThroughList(List<YourInterface> list){
list.forEach(yourInterface -> System.out.println(yourInterface.getText()));
}
Sample usage.
public static void main(String[] args) {
loopThroughList(getList(1));
loopThroughList(getList(2));
}
Interfaces work great here, but there a couple of other options if you're dealing with legacy code and cannot use interfaces.
First would be to cast the list items into their respective types:
for (Object o : lists.getList(listNumber)) {
if(o instanceof Object1) {
Object1 o1 = (Object1)o;
System.out.println(o1.getText());
}
else if(o instanceof Object2) {
Object1 o2 = (Object2)o;
System.out.println(o2.getText());
}
else {
System.out.println("Unknown class");
}
}
You can also use reflection to see if the object has a getText method and then invoke it:
for (Object o : lists.getList(listNumber)) {
try {
System.out.println(o.getClass().getDeclaredMethod("getName").invoke(o));
}
catch(Exception e) {
System.out.println("Object doesn't have getText method");
}
}
This is awful. Can you elaborate on what specifically you are trying to do? Java is strong typed by design, and you are trying to get around it. Why? Instead of Object, use the specific class, or interface as previously suggested. If that's not possible, and you must use lists of Objects, use instanceof and casting eg:
for (Object o : lists.getList(listNumber)) {
if (o instanceof Object1) {
Object1 o1 = (Object1) o;
System.out.println(o1.getText());
} else if (o instanceof Object2) {
Object2 o2 = (Object2) o;
System.out.println(o2.getText());
}
}
This is where interfaces come in.
interface HasText {
public String getText();
}
class Object1 implements HasText {
#Override
public String getText() {
return "1";
}
}
class Object2 implements HasText {
#Override
public String getText() {
return "2";
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2());
for (HasText ht : list) {
System.out.println(ht);
}
}
If one of your objects is not in your control you can use a Wrapper class.
class Object3DoesNotImplementHasText {
public String getText() {
return "3";
}
}
class Object3Wrapper implements HasText{
final Object3DoesNotImplementHasText it;
public Object3Wrapper(Object3DoesNotImplementHasText it) {
this.it = it;
}
#Override
public String getText() {
return it.getText();
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2(), new Object3Wrapper(new Object3DoesNotImplementHasText()));
for (HasText ht : list) {
System.out.println(ht);
}
}
Just to add more to this answer and give you some more to think on this (Will try to do it in a simple, non-formal way). Using interfaces is the proper way of doing such operation. However, I want to stand on the "bad idea":
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
What you are doing here, is using a mechanism called Reflection:
Reflection is a feature in the Java programming language. It allows an
executing Java program to examine or "introspect" upon itself, and
manipulate internal properties of the program. For example, it's
possible for a Java class to obtain the names of all its members and
display them.
What you actually attempted, is using that mechanism, to retrieve the method through a Class reflection object instance of your Class (sounds weird, isn't it?).
From that perspective, you need to think that, if you want to invoke your method, you now have, in a sense, a meta-Class instance to manipulate your objects. Think of it like an Object that is one step above your Objects (Similarly to a dream inside a dream, in Inception). In that sense, you need to retrieve the method, and then invoke it in a different (meta-like) way:
java.lang.reflect.Method m = o.getClass().getMethod("getText");
m.invoke(o);
Using that logic, you could possibly iterate through the object list, check if method exists, then invoke your method.
This is though a bad, BAD idea.
Why? Well, the answer relies on reflection itself: reflection is directly associated with runtime - i.e. when the program executes, practically doing all things at runtime, bypassing the compilation world.
In other words, by doing this, you are bypassing the compilation error mechanism of Java, allowing such errors happen in runtime. This can lead to unstable behavior of the program while executing - apart from the performance overhead using Reflection, which will not analyze here.
Side note: While using reflection will require the usage of Checked Exception handling, it still is not a good idea of doing this - as you practically try to duck tape a bad solution.
On the other hand, you can follow the Inheritance mechanism of Java through Classes and Interfaces - define an interface with your method (let's call it Textable), make sure that your classes implement it, and then use it as your base object in your list declaration (#alexrolea has implemented this in his answer, as also #OldCurmudgeon has).
This way, your program will still make the method call decision making at Runtime (via a mechanism called late binding), but you will not bypass the compilation error mechanism of Java. Think about it: what would happen if you define a Textable implementation without providing the class - a compile error! And what if you set a non-Textable object into the list of Textables? Guess what! A compile error again. And the list goes on....
In general, avoid using Reflection when you are able to do so. Reflection is useful in some cases that you need to handle your program in such a meta-way and there is no other way of making such things. This is not the case though.
UPDATE: As suggested by some answers, you can use instanceof to check if you have a specific Class object instance that contains your method, then invoke respectively. While this seems a simple solution, it is bad in terms of scaling: what if you have 1000 different classes that implement the same method you want to call?
your objects have to implement a common interface.
interface GetTextable {
String getText();
}
class One implements GetTextable {
private final String text;
public One(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
class Two implements GetTextable {
private final String text;
public Two(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
#Test
public void shouldIterate() throws Exception {
List<GetTextable> toIterate = Arrays.asList(new One("oneText"), new Two("twoText"));
for(GetTextable obj: toIterate) {
System.out.println(obj.getText());
}
}

Standard pattern of initiating and calling the Java method references

I have a ClassA object that sets method references inside of ClassB1 and ClassB2 objects. ClassB1 and ClassB2 objects will later use this method reference while running their methods. But, sometimes we do not set the method reference:
public class ClassA {
public ClassA() {
ClassB1 objB1 = new ClassB1();
ClassB2 objB2 = new ClassB2();
objB1.setFuncitonA(this::functionA);
objB2.setFuncitonA(this::functionA);
objB1.functionB();
objB2.functionB();
}
public void functionA(Integer x) {
x *= 2;
}
}
public class ClassB1 {
private Integer intObjB = new Integer(2);
private Consumer<Integer> functionA = null;
public void functionB() {
if(functionA != null) {
functionA.accept(intObjB);
}
}
public void setFuncitonA(Consumer<Integer> functionA) {
this.functionA = functionA;
}
}
public class ClassB2 {
private Integer intObjB = new Integer(2);
private Consumer<Integer> functionA = this::defaultFunctionA;
public void functionB() {
functionA.accept(intObjB);
}
public void setFuncitonA(Consumer<Integer> functionA) {
this.functionA = functionA;
}
public void defaultFunctionA(Integer intObj) {
return;
}
}
Should it be like in ClassB1 or like in ClassB2, or, does it matter at all? What is the standard pattern of writing such code?
There is nomenclature for this sort of implementation decision: lazily instantiating your field, or eagerly instantiating your field.
ClassB1 lazily instantiates the functionA consumer. This tells a maintainer (including yourself) that this consumer isn't always necessary for every new instance, and having it null in certain contexts is safe. It does mean that you have to look over your shoulder when you're using it though, as in the case of the null checks.
ClassB2 eagerly instantiates the functionA consumer. This tells a maintainer (including yourself) that this consumer is required at instantiation time. This means you avoid the silly null check if it's truly something you know at instantiation time (and in this case, it is something you either know or can get).
The standard pattern then becomes:
If you're comfortable checking that the field (or variable) is null before use, then lazily instantiate the field.
If you must be sure that the field (or variable) is not null before use, then eagerly instantiate the field.
There's no hard and fast rule to use or prefer one over the other. This will heavily depend on your use case.
Eliminating if statements is always preferred.
Also, eliminating null variables is always better.
Therefore, the ClassB2 approach is better by far.

lateinit, lazy and singleton pattern in kotlin

I'm trying to convert some part of my project from java to kotlin. One of it is a singleton manager class. The java class looks like this
public class Manager {
private static volatile Manager Instance = null;
private static final Object InstanceLock = new Object();
private Manager(Object1 object1, Object2 object2, Object3 object3){//...};
public static boolean isInitialized(){
synchronized(InstanceLock){
return Instance == null;
}
}
public static void initialize(Object1 object1, Object2 object2, Object3 object3){
if(Instance == null){
synchronized(InstanceLock){
if(Instance == null){Instance = new Manager(object1, object2, object3};
}
}
}
public static getInstance(){
Precondition.checkNotNull(Instance, msg...);
return Instance;
}
}
Also, I decompiled .kt back to java. In the companion class I get the following code.
public static final class Companion {
#Nullable
public final Manager getInstance() {
return Manager.instance;
}
private final void setInstance(Manager var1) {
Manager.instance = var1;
}
private final Object getInstanceLock() {
return Manager.InstanceLock;
}
public final boolean isInitialized() {
Object var1 = Manager.Companion.getInstanceLock();
synchronized(var1){}
boolean var4;
try {
var4 = Manager.Companion.getInstance() == null;
} finally {
;
}
return var4;
}
public final void initialize(#NotNull String string1, #NotNull String string2) {
Intrinsics.checkParameterIsNotNull(string1, "string1");
Intrinsics.checkParameterIsNotNull(string2, "string2");
if (((Manager.Companion)this).getInstance() == null) {
Object var3 = ((Manager.Companion)this).getInstanceLock();
synchronized(var3){}
try {
if (Manager.Companion.getInstance() == null) {
Manager.Companion.setInstance(new Manager(string1, string2, (DefaultConstructorMarker)null));
}
Unit var5 = Unit.INSTANCE;
} finally {
;
}
}
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
1) How do I achieve thread safety, singleton by using lateinit or lazy inside the kotlin companion object ? As I can see, the decompiled java code has a synchronized call in initialize function but nothing in the synchronize body.
2) I think kotlin object/lazy comes with thread safety guarantee, how do I take advantage of it in the double-checked locking pattern ?
3) Is there a better pattern than double-checked locking pattern? Assuming the constructor does need arguments.
4) Since I'm trying to make the impact of converting this manager class to kotlin file as small as possible (this Manager file is supposed to work with the rest of java code), what is the best approach ? I do notice I have to add #Jvmstatic or #Jvmfield in some other variables or functions inside of companion object so that I don't have to update other java file that has call to these static field in manager.
5) Additional question, what if this manager is now working in pure kotlin environment, what's the best practice of implementing a singleton class with multiple arguments ?
The first answer does not address the synchronization, which, btw, is still an under appreciated complexity. There are still a ton of people running around saying simply do double-checked locking. But there are some pretty compelling arguments that show that DCL does not always work.
Interestingly, though, I had this same issue recently and found this article. While I did not like this the first time I found it, I revisited it a few times and warmed up to it, in large part because:
the author went and got code from the Kotlin stdlib
the result is a parameterized mechanism that while kind of ugly affords reuse, which is pretty compelling
Notice that the major issues are all broached in this treatment:
synchronization
complex initialization
parameterized initialization (crucial in Android, where the Context god object is ineradicable)
resulting compiled code
In short I think this is pretty much the first and last word on this topic, amazingly, found on Medium.
I don't have answer to all of your questions, but there is a defined way to create a singleton class in Kotlin.
Instead of class prefix in front of the class name, use object.
For example,
object Manager {
// your implementation
}
This make this class singleton and you can directly use this from Java like Manager.getInstance() (I didn't remeber the exact syntax but this should work) . Kotlin creates it for you.
You can check this for more reference.
Hope it will help you a little.

Refering "this" in a lazy initialization supplier?

For business decision applications, I run into a lot of cases where I must cache an expensive value with lazy initialization. So I leveraged generics and a Supplier lambda to encapsulate a lazy initialization.
import java.util.function.Supplier;
public final class LazyProperty<T> {
private final Supplier<T> supplier;
private volatile T value;
private LazyProperty(Supplier<T> supplier) {
this.supplier = supplier;
}
public T get() {
if (value == null) {
synchronized(this) {
if (value == null) {
value = supplier.get();
}
}
}
return value;
}
public static <T> LazyProperty<T> forSupplier(Supplier<T> supplier) {
return new LazyProperty<T>(supplier);
}
}
But I'd like to be able to use this also in cases where I can't initialize a property until after the object is created, because the object can only calculate this property after it is created (usually needing context of itself or other objects). However, this often requires a reference to this in the supplier function.
public class MyClass {
private final LazyProperty<BigDecimal> expensiveVal =
LazyProperty.forSupplier(() -> calculateExpensiveVal(this));
public BigDecimal getExpensiveVal() {
return expensiveVal.get();
}
}
As long as I can guarantee the LazyProperty's get() function is only called after MyClass is constructed (via the getExpensiveVal() method), there shouldn't be any partial construction issues due to the this reference in the supplier, correct?
Based on the little code you showed you should not have any problems but I would probably write your class like this to be more explicit:
public class MyClass {
private final LazyProperty<BigDecimal> expensiveVal;
public MyClass() {
this.expensiveVal = LazyProperty.forSupplier(() -> calculateExpensiveVal(MyClass.this));
}
public BigDecimal getExpensiveVal() {
return expensiveVal.get();
}
}
Your code will have one Problem which depends on the implementation of method calculateExpensiveVal.
if calculateExpensiveVal calls getExpensiveVal on the passed reference of MyClass you will get NullPointerException.
if calculateExpensiveVal creates a thread and pass the reference of MyClass, again you may run into the same problem as point 1.
But if you guarantee calculateExpensiveVal is not doing any of the things, then your code stand correct from Thread safety Perspective. MyClass will never be seen partially constructed
because of the final gaurantees provided by the JMM
After saying that even though your *calculateExpensiveVal may employ any one or both those points you are only going to have problem in getExpensiveVal method with NullPointerException.
your lazyProperty.get method is already thread safe so there woun'd be any problem.
Because you will always see fully constructed Supplier object because of final keyword (only if you didn't escaped 'this' reference to another thread) and you already have used volatile for value field which takes care of seeing fully constructed value object.

How to make a java proxy object to java.nio.ByteBuffer instance?

I have a public abstract class java.nio.ByteBuffer instance which is actually an instance of private class java.nio.HeapByteBuffer and I need to make a proxy object which would call some invocation method handler to check access permissions and then call the invoked method on the actual instance.
The problem is that the java.nio.ByteBuffer class has only private constructors and also has some final methods, thus I can not create proxy instances with javassist.util.proxy.ProxyFactory class.
So, how can I make a proxy object to control the invocation of a java.nio.ByteBuffer instance including those final methods invocation?
Please be aware that I am presenting a solution based on my own (FOSS) framework Byte Buddy which is however already mentioned as a potential solution in one of the comments.
Here is a simple proxy approach which creates a subclass. First, we introduce a type for creating proxies for ByteBuffers:
interface ByteBufferProxy {
ByteBuffer getOriginal();
void setOriginal(ByteBuffer byteBuffer);
}
Furthermore, we need to introduce an interceptor to use with a MethodDelegation:
class Interceptor {
#RuntimeType
public static Object intercept(#Origin(cacheMethod = true) Method method,
#This ByteBufferProxy proxy,
#AllArguments Object[] arguments)
throws Exception {
// Do stuff here such as:
System.out.println("Calling " + method + " on " + proxy.getOriginal());
return method.invoke(proxy.getOriginal(), arguments);
}
}
This interceptor is capable of intercepting any method as the #RuntimeType casts the return type in case that it does not fit the Object signature. As you are merely delegating, you are safe. Plase read the documentation for details. As you can see from the annotations, this interceptor is only applicable for instances of ByteBufferProxy. Bases on this assumption, we want to:
Create a subclass of ByteBuffer.
Add a field to store the original (proxied) instance.
Implement ByteBufferProxy and implement the interface methods to access the field for the stored instance.
Override all other methods to call the interceptor that we defined above.
This we can do as follows:
#Test
public void testProxyExample() throws Exception {
// Create proxy type.
Class<? extends ByteBuffer> proxyType = new ByteBuddy()
.subclass(ByteBuffer.class)
.method(any()).intercept(MethodDelegation.to(Interceptor.class))
.defineField("original", ByteBuffer.class, Visibility.PRIVATE)
.implement(ByteBufferProxy.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
// Create fake constructor, works only on HotSpot. (Use Objenesis!)
Constructor<? extends ByteBufferProxy> constructor = ReflectionFactory
.getReflectionFactory()
.newConstructorForSerialization(proxyType,
Object.class.getDeclaredConstructor());
// Create a random instance which we want to proxy.
ByteBuffer byteBuffer = ByteBuffer.allocate(42);
// Create a proxy and set its proxied instance.
ByteBufferProxy proxy = constructor.newInstance();
proxy.setOriginal(byteBuffer);
// Example: demonstrates interception.
((ByteBuffer) proxy).get();
}
final methods are obviously not intercepted. However as the final methods in ByteBuffer only serve as convenience methods (e.g. put(byte[]) calls put(byte[],int,int) with the additional arguments 0 and the array length), you are still able to intercept any method invocation eventually as these "most general" methods are still overridable. You could even trace the original invocation via Thread.currentCallStack().
Byte Buddy normally copies all constructors of its super class if you do not specify another ConstructorStrategy. With no accessible constructor, it simply creates a class without constructors what is perfectly legal in the Java class file format. You cannot define a constructor because, by definition, this constructor would need to call another constructor what is impossible. If you defined a constructor without this property, you would get a VerifierError as long as you do not disable the verifier altogether (what is a terrible solution as it makes Java intrinsically unsafe to run).
Instead, for instantiation, we call a popular trick that is used by many mocking frameworks but which requires an internal call into the JVM. Note that you should probably use a library such as Objenesis instead of directly using the ReflectionFactory because Objenesis is more robust when code is run on a different JVM than HotSpot. Also, rather use this in non-prduction code. Do however not worry about performance. When using a reflective Method that can be cached by Byte Buddy for you (via cacheMethod = true), the just-in-time compiler takes care of the rest and there is basically no performance overhead (see the benchmark on bytebuddy.net for details.) While reflective lookup is expensive, reflective invocation is not.
I just released Byte Buddy version 0.3 and I am currently working on documentation. In Byte Buddy 0.4, I plan to introduce an agent builder which allows you to redefine classes during load-time without knowing a thing about agents or byte code.
I can suggest you 2 solutions.
First, simple, not universal, but probably useful for you.
As far as I can see ByteBuffer has several package-private constructors that allow its subclassing and the following final methods:
public final ByteBuffer put(byte[] src) {
public final boolean hasArray() {
public final byte[] array() {
public final int arrayOffset() {
public final ByteOrder order() {
ByteBuffer extends Buffer that declares some of these methods:
public final boolean hasArray() {
public final Object array() {
public final int arrayOffset() {
As you can see, put() and order() are absent here, return type of array() is a little bit confusing, but still can be used.
So, if you use only these 3 methods you can subclass Buffer and create universal wrapper that wraps any other Buffer including ByteBuffers. If you want you can use javaassist's proxy although IMHO it is not necessarily here.
Second, more universal but more tricky solution. You can create agent that removes final modifiers from speicific class (ByteBuffer in your case) during class loading. Then you can create javassist proxy.
Variation of second solution is following. Copy ByteBuffer soruce code to separate project. Remove final modifiers and compile it. Then push it into bootstrap classpath. This solutions is probably easier than second.
Good luck anyway.
Thanks to #raphw I have managed to make a proxy object construction class which makes a proxy for java.nio.ByteBuffer but that class has final methods which I can not overcome and they are extensively used in the required code, those final methods are Buffer.remaining() and Buffer.hasRemaining(), thus they just can not be proxy mapped.
But I would like to share the classes I have made, just as a report.
public final class CacheReusableCheckerUtils {
private static ByteBuddy buddy = new ByteBuddy();
private static Objenesis objenesis = new ObjenesisStd();
public static <T> T createChecker(T object) {
return createChecker(new CacheReusableCheckerInterceptor<>(object));
}
public static <T> T createChecker(CacheReusableCheckerInterceptor<T> interceptor) {
return objenesis.getInstantiatorOf(createCheckerClass(interceptor)).newInstance();
}
private static <T> Class<? extends T> createCheckerClass(CacheReusableCheckerInterceptor<T> interceptor) {
Class<T> objectClass = interceptor.getObjectClass();
Builder<? extends T> builder = buddy.subclass(objectClass);
builder = builder.implement(CacheReusableChecker.class).intercept(StubMethod.INSTANCE);
builder = builder.method(MethodMatchers.any()).intercept(MethodDelegation.to(interceptor));
return builder.make().load(getClassLoader(objectClass, interceptor), Default.WRAPPER).getLoaded();
}
private static <T> ClassLoader getClassLoader(Class<T> objectClass, CacheReusableCheckerInterceptor<T> interceptor) {
ClassLoader classLoader = objectClass.getClassLoader();
if (classLoader == null) {
return interceptor.getClass().getClassLoader();
} else {
return classLoader;
}
}
}
public class CacheReusableCheckerInterceptor<T> {
private T object;
private boolean allowAccess;
private Throwable denyThrowable;
public CacheReusableCheckerInterceptor(#NotNull T object) {
this.object = object;
}
#SuppressWarnings("unchecked")
public Class<T> getObjectClass() {
return (Class<T>) object.getClass();
}
#RuntimeType
public final Object intercept(#Origin(cacheMethod = true) Method method, #This T proxy, #AllArguments Object[] arguments) {
try {
switch (method.getName()) {
case "allowAccess":
allowAccess();
return null;
case "denyAccess":
denyAccess();
return null;
default:
return invokeMethod(method, arguments);
}
} catch (Exception e) {
throw new CacheReusableCheckerException(method, object, proxy, e);
}
}
private Object invokeMethod(Method method, Object[] arguments) throws IllegalAccessException, InvocationTargetException {
checkMethodAccess(method.getName());
return method.invoke(object, arguments);
}
private void allowAccess() {
if (allowAccess) {
error("double use");
}
allowAccess = true;
onAccessAllowedAfter(object);
}
private void denyAccess() {
if (!allowAccess) {
error("double free");
}
onAccessDeniedBefore(object);
allowAccess = false;
denyThrowable = new Throwable();
}
private void checkMethodAccess(String name) {
if (!allowAccess) {
switch (name) {
case "hash":
case "equals":
case "toString":
case "finalize":
break;
default:
error("use after free");
}
}
}
private void error(String message) {
throw new CacheReusableCheckerException(message, denyThrowable);
}
protected void onAccessAllowedAfter(T object) {
}
protected void onAccessDeniedBefore(T object) {
}
}
public interface CacheReusableChecker {
void allowAccess();
void denyAccess();
}

Categories

Resources