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

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();
}

Related

Replace a reflective call with a dynamically generated class

I have an interface similar to this:
public interface Getter {
Object get(Params params);
}
that I implement using a reflective call to a different method:
public class GetterImpl implements Getter {
private final Object target;
private final Method method; //doStuff method
public GetterImpl(Object target, Method method) {
this.target = target;
this.method = method;
}
#Override
public Object get(Params params) {
//both the target and arguments depend on Params
return method.invoke(chooseTarget(params), prepareArgs(params));
}
private Object chooseTarget(Params params) {
if (params.getTargetOverride() != null) {
return params.getTargetOverride();
}
return target;
}
private Object[] prepareArgs(Params params) {
...
}
}
Is it possible to instead generate a class implementing Getter with equivalent logic but without reflection? Effectively a class like this:
public class GeneratedGetterImpl implements Getter {
...
#Override
public Object get(Params params) {
//somehow call doStuff directly (different method for each generated impl)
return target.doStuff(prepareArgs(params));
}
}
I'm looking into using Byte Buddy to generate such a class on the fly, but all the examples provide some sort of statically known method interceptor, and never delegate to a dynamically chosen target and method.
It's clearly not a trivial task, but can this be done with Byte Buddy? Or a different library?
UPDATE:
Here's my best attempt so far:
Target target = new Target();
Method method = Target.class.getMethod("doStuff", Book.class);
//Helper class that computes the new arguments based on the original
Prepare prepare = new Prepare();
Method doPrep = Prepare.class.getMethod("doPrep", Params.class);
Getter getter = (Getter) new ByteBuddy()
.subclass(Object.class)
.implement(Getter.class)
.method(named("get")).intercept(
MethodCall.invoke(method).on(target)
.withMethodCall(
MethodCall.invoke(doPrep).on(prepare).withAllArguments()
))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance();
public static class Prepare {
public Book doPrep(Params params) {
return new Book(params.getTitle());
}
}
This does what I want, but only if the targeted method takes 1 argument (Book in my case). I'm struggling to figure out how to have it return an array that I then spread when calling the target method.
E.g.
public static class Prepare {
//returns all the arguments
public Object[] doPrep(Params params) {
return new Object[] { new Book(params.getTitle()) };
}
}
Such a facility does already exists in the JRE, if we restrict it to binding an interface to a matching target method.
public static void main(String[] args) throws NoSuchMethodException {
Function<Double,Double> f1 = create(Math.class.getMethod("abs", double.class));
System.out.println(f1.apply(-42.0));
Map<Double,Double> m = new HashMap<>();
Function<Double,Double> f2 = create(Map.class.getMethod("get", Object.class), m);
m.put(1.0, 123.0);
System.out.println(f2.apply(1.0));
}
static Function<Double,Double> create(Method m) {
MethodHandles.Lookup l = MethodHandles.lookup();
MethodType t = MethodType.methodType(Double.class, Double.class);
try {
return (Function)LambdaMetafactory.metafactory(l, "apply",
MethodType.methodType(Function.class), t.erase(), l.unreflect(m), t)
.getTarget().invoke();
} catch(Throwable ex) {
throw new IllegalStateException(ex);
}
}
static Function<Double,Double> create(Method m, Object target) {
MethodHandles.Lookup l = MethodHandles.lookup();
MethodType t = MethodType.methodType(Double.class, Double.class);
try {
return (Function)LambdaMetafactory.metafactory(l, "apply",
MethodType.methodType(Function.class, m.getDeclaringClass()),
t.erase(), l.unreflect(m), t)
.getTarget().invoke(target);
} catch(Throwable ex) {
throw new IllegalStateException(ex);
}
}
42.0
123.0
This demonstrates that adaptations like auto-boxing and casting as required for generic functions are included, but any other adaptations of parameters or results are not possible and have to be performed by pre-existing decorating code. Most notably, varargs processing is not included.
The documentation is exhaustive. It’s strongly recommended to read it in all details before using the class. But the things you can do wrong here, are similar to the things you can do wrong when implementing your own bytecode generator.
Using Byte Buddy, you can create a MethodCall instance that represents your proxied method and use it as an implementation. I assume that you looked into delegation which requires a more static model:
MethodCall.invoke(SomeClass.class.getMethod("foo")).with(...)
You can also provide other method call instances as arguments to methods to achieve what you have in your example code.
As for your updated question, I'd recommend you a hybrid approach. Implement some container:
class Builder<T> {
Builder with<T>(T value);
T[] toArray();
}
and then you can use Byte Buddy to invoke it for creating your result value:
MethodCall builder = MethodCall.construct(Builder.class.getConstructor());
for (SomeInfoObject info : ...) {
builder = MethodCall.invoke(Builder.class.getMethod("with", Object.class))
.on(builder)
.with(toMethodCall(info));
}
builder = MethodCall.invoke(Builder.class.getMethod("toArray")).on(builder);
Byte Buddy's goal is to make weaving code easy, not to replace writing static code which is the much better option if you have the opportunity.

Why a public static method is not accessible?

I'm trying to reflect the parse(CharSequence, DateTimeFormatter) methods from classes which each extends the TemporalAccessor class.
private static final Map<Class<?>, MethodHandle> PARSE_HANDLES = synchronizedMap(new HashMap<>());
static <T extends TemporalAccessor> MethodHandle parseMethodHandle(final Class<T> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz is null");
}
return PARSE_HANDLES.computeIfAbsent(clazz, k -> {
try {
final Method method = clazz.getMethod("parse", CharSequence.class, DateTimeFormatter.class);
log.debug("method: {}, {}", method, method.isAccessible());
// i don't understand; public static method is not accessible? yet it isn't.
assert method.isAccessible(); // NOT GOOD with UTs
return MethodHandles.lookup().unreflect(method);
} catch (final ReflectiveOperationException roe) {
throw new RuntimeException(roe);
}
});
}
With the YearMonth class, I got this.
method: public static java.time.YearMonth java.time.YearMonth.parse(java.lang.CharSequence,java.time.format.DateTimeFormatter), false
Why a public static method is not accessible?
See the documentation for isAccessible:
This method is deprecated because its name hints that it checks if the reflected object is accessible when it actually indicates if the checks for Java language access control are suppressed. This method may return false on a reflected object that is accessible to the caller. To test if this reflected object is accessible, it should use canAccess(Object).
(My emphasis.)
With the Java Reflection API, you can override the accessibility of methods by setting the accessible flag. This can be performed by method.setAccessible(true).
Now the isAccessible() method does not what you think it does, but it simply checks, if the standard java access checks are currently overridden.
This means, that you can of course invoke the method with reflection if the standard access modifiers allow it. Otherwise, you had to set the accessible flag.

make subclass serialize as an instance of the super class?

im dealing with a codebase that has builds MBeans (for export to jmx).
the original code simply builds an MBeanInfo instance:
#Override
public MBeanInfo getMBeanInfo() {
MBeanAttributeInfo[] attrs = //SLOW TO BUILD
return new MBeanInfo(...attrs...);
}
since the mbean attributes are expensive to build, and this method get called rather frequently (even with no jmx clients attached), i've tried creating a subclass of MBeanInto that lazily calculates those attributes:
public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
private transient AttributeCallback callback = null;
private volatile MBeanAttributeInfo[] lazyAttrs = null;
public LazyMBeanInfo(...AttributeCallback callback...) throws IllegalArgumentException {
super(className, description, null, constructors, operations, notifications);
this.callback = callback;
}
#Override
public MBeanAttributeInfo[] getAttributes() {
MBeanAttributeInfo[] val = lazyAttrs;
if (val != null) {
return val.clone(); //match upstream behaviour
}
if (callback == null) {
throw new IllegalStateException("BUG");
}
val = callback.buildAttributes();
if (val == null) {
val = new MBeanAttributeInfo[0];
}
lazyAttrs = val;
return val.clone();
}
public interface AttributeCallback {
MBeanAttributeInfo[] buildAttributes();
}
}
the problem is that JMX (over RMI) serializes the MBeanInfo object, and then in jconsole (or jvisualVM) i get an error:
so - can i somehow implement Externalizable and serialize myself as an instance of the parent class? ideally i'd like this to work:
public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
//same as before, plus:
#Override
public void writeExternal(ObjectOutput out) throws IOException {
MBeanInfo vanilla = new MBeanInfo(...);
out.writeObject(vanilla);
}
}
but it doesnt.
is this possible somehow ?
Unless you are using [highly dynamic] DynamicMBeans, I don't see why the MBeanInfo needs to be rebuilt for every call to getMBeanInfo(), but ....
Your LazyMBeanInfo can be made to work (though I have not tested this specific case). MBeanInfo already implements Serializable, so what you want is for the serialization process to write out an MBeanInfo, not a LazyMBeanInfo, since the client probably doesn't have that class in its classpath. However, LazyMBeanInfo can implement this method:
Object writeReplace() throws ObjectStreamException;
at which point you write out the underlying MBeanInfo. See the Serializable JavaDoc, specifically:
Serializable classes that need to designate an alternative object to
be used when writing an object to the stream should implement this
special method with the exact signature:
ANY-ACCESS-MODIFIER Object writeReplace() throws
ObjectStreamException;
In that way, the actual object can be an instance of LazyMBeanInfo, but what you write out can be an actual MBeanInfo, built from your cached lazyAttrs.
Having said that, rather than implementing a build-on-first-call approach, I would implement a build-before-first-use by simply building the full MBeanInfo when the MBean is first created, or when the MBean is registered. Then just return the pre-built MBeanInfo on each getMBeanInfo() call.
To do this at MBean registration time, implement the MBeanRegistration interface, and build the cached MBeanInfo in the postRegister method.

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

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
}
});
}
}

How to Avoid Constructor calling During Object Creation?

I want to avoid the constructor calling during object creation in java (either default constructor or user defined constructor) . Is it possible to avoid constructor calling during object creation???
Thanks in advance......
Simply extract the intialization logic that you want to avoid into another method called init. You can not avoid calling exactly one constructor.
No matter what pattern or strategy you use, at some point your will need to call a constructor if you want to create an object.
Actually, its possible under some circumstances by using classes from the JVM implementation (which do not belong to the JRE API and are implemenation specific).
One example here http://www.javaspecialists.eu/archive/Issue175.html
It should also be possible using sun.misc.Unsafe.allocateInstance() (Java7)
Also, the constructor is apparently bypassed when using the clone()-method to create a copy of an object (and the class doesn't override clone to implement it different from the Object.clone() method).
All of these possibilities come with strings attached and should be used carefully, if at all.
You can mock the constructors of a class. They will still be called, but not executed. For example, the following JUnit+JMockit test does that:
static class CodeUnderTest
{
private final SomeDependency someDep = new SomeDependency(123, "abc");
int doSomething(String s)
{
someDep.doSomethingElse(s);
return someDep.getValue();
}
}
static final class SomeDependency
{
SomeDependency(int i, String s) { throw new RuntimeException("won't run"); }
int getValue() { return -1; }
}
#Test
public void mockEntireClassIncludingItsConstructors()
{
new NonStrictExpectations() {
#Mocked SomeDependency mockDep;
{ mockDep.getValue(); result = 123; }
};
int result = new CodeUnderTest().doSomething("testing");
assertEquals(123, result);
}

Categories

Resources