Search in sources :

Example 1 with ProxyFactory

use of io.quarkus.deployment.proxy.ProxyFactory in project quarkus by quarkusio.

the class BytecodeRecorderImpl method getRecordingProxy.

public <T> T getRecordingProxy(Class<T> theClass) {
    if (existingProxyClasses.containsKey(theClass)) {
        return theClass.cast(existingProxyClasses.get(theClass));
    }
    NewRecorder newRecorder = new NewRecorder(theClass);
    existingRecorderValues.put(theClass, newRecorder);
    InvocationHandler invocationHandler = new InvocationHandler() {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (staticInit) {
                for (int i = 0; i < args.length; ++i) {
                    if (args[i] instanceof ReturnedProxy) {
                        ReturnedProxy p = (ReturnedProxy) args[i];
                        if (!p.__static$$init()) {
                            throw new RuntimeException("Invalid proxy passed to recorder. Parameter " + i + " of type " + method.getParameterTypes()[i] + " was created in a runtime recorder method, while this recorder is for a static init method. The object will not have been created at the time this method is run.");
                        }
                    }
                }
            }
            StoredMethodCall storedMethodCall = new StoredMethodCall(theClass, method, args);
            storedMethodCalls.add(storedMethodCall);
            Class<?> returnType = method.getReturnType();
            if (method.getName().equals("toString") && method.getParameterCount() == 0 && returnType.equals(String.class)) {
                return proxy.getClass().getName();
            }
            boolean voidMethod = method.getReturnType().equals(void.class);
            if (!voidMethod && !isProxiable(method.getReturnType())) {
                throw new RuntimeException("Cannot use " + method + " as a recorder method as the return type cannot be proxied. Use RuntimeValue to wrap the return value instead.");
            }
            if (voidMethod) {
                return null;
            }
            ProxyInstance instance = getProxyInstance(returnType);
            if (instance == null) {
                return null;
            }
            storedMethodCall.returnedProxy = instance.proxy;
            storedMethodCall.proxyId = instance.key;
            return instance.proxy;
        }
    };
    try {
        if (recordingProxyFactories.containsKey(theClass)) {
            return (T) recordingProxyFactories.get(theClass).newInstance(invocationHandler);
        }
        String proxyNameSuffix = "$$RecordingProxyProxy" + COUNT.incrementAndGet();
        ProxyConfiguration<T> proxyConfiguration = new ProxyConfiguration<T>().setSuperClass(theClass).setClassLoader(classLoader).setAnchorClass(getClass()).setProxyNameSuffix(proxyNameSuffix);
        ProxyFactory<T> factory = new ProxyFactory<T>(proxyConfiguration);
        T recordingProxy = factory.newInstance(invocationHandler);
        existingProxyClasses.put(theClass, recordingProxy);
        recordingProxyFactories.put(theClass, factory);
        if (theClass.getClassLoader() instanceof QuarkusClassLoader) {
            ((QuarkusClassLoader) theClass.getClassLoader()).addCloseTask(new Runnable() {

                @Override
                public void run() {
                    recordingProxyFactories.remove(theClass);
                }
            });
        }
        return recordingProxy;
    } catch (IllegalAccessException | InstantiationException e) {
        throw new RuntimeException(e);
    }
}
Also used : ProxyFactory(io.quarkus.deployment.proxy.ProxyFactory) Method(java.lang.reflect.Method) MethodDescriptor.ofMethod(io.quarkus.gizmo.MethodDescriptor.ofMethod) InvocationHandler(java.lang.reflect.InvocationHandler) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) ProxyConfiguration(io.quarkus.deployment.proxy.ProxyConfiguration)

Example 2 with ProxyFactory

use of io.quarkus.deployment.proxy.ProxyFactory in project quarkus by quarkusio.

the class BytecodeRecorderImpl method getProxyInstance.

private ProxyInstance getProxyInstance(Class<?> returnType) throws InstantiationException, IllegalAccessException {
    boolean returnInterface = returnType.isInterface();
    ProxyFactory<?> proxyFactory = returnValueProxy.get(returnType);
    if (proxyFactory == null) {
        ProxyConfiguration<Object> proxyConfiguration = new ProxyConfiguration<Object>().setSuperClass(returnInterface ? Object.class : (Class) returnType).setClassLoader(classLoader).addAdditionalInterface(ReturnedProxy.class).setAnchorClass(getClass()).setProxyNameSuffix("$$ReturnValueProxy" + COUNT.incrementAndGet());
        if (returnInterface) {
            proxyConfiguration.addAdditionalInterface(returnType);
        }
        returnValueProxy.put(returnType, proxyFactory = new ProxyFactory<>(proxyConfiguration));
    }
    String key = PROXY_KEY + COUNT.incrementAndGet();
    Object proxyInstance = proxyFactory.newInstance(new InvocationHandler() {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("__returned$proxy$key")) {
                return key;
            }
            if (method.getName().equals("__static$$init")) {
                return staticInit;
            }
            if (method.getName().equals("toString") && method.getParameterCount() == 0 && method.getReturnType().equals(String.class)) {
                return "Runtime proxy of " + returnType + " with id " + key;
            }
            if (method.getName().equals("hashCode") && method.getParameterCount() == 0 && method.getReturnType().equals(int.class)) {
                return System.identityHashCode(proxy);
            }
            if (method.getName().equals("equals") && method.getParameterCount() == 1 && method.getParameterTypes()[0] == Object.class && method.getReturnType().equals(boolean.class)) {
                return proxy == args[0];
            }
            throw new RuntimeException("You cannot invoke " + method.getName() + "() directly on an object returned from the bytecode recorder, you can only pass it back into the recorder as a parameter");
        }
    });
    return new ProxyInstance(proxyInstance, key);
}
Also used : ProxyFactory(io.quarkus.deployment.proxy.ProxyFactory) Method(java.lang.reflect.Method) MethodDescriptor.ofMethod(io.quarkus.gizmo.MethodDescriptor.ofMethod) InvocationHandler(java.lang.reflect.InvocationHandler)

Aggregations

ProxyFactory (io.quarkus.deployment.proxy.ProxyFactory)2 MethodDescriptor.ofMethod (io.quarkus.gizmo.MethodDescriptor.ofMethod)2 InvocationHandler (java.lang.reflect.InvocationHandler)2 Method (java.lang.reflect.Method)2 QuarkusClassLoader (io.quarkus.bootstrap.classloading.QuarkusClassLoader)1 ProxyConfiguration (io.quarkus.deployment.proxy.ProxyConfiguration)1