use of org.mule.runtime.core.internal.util.CompositeClassLoader in project mule by mulesoft.
the class AnnotatedObjectInvocationHandler method addAnnotationsToClass.
/**
* Enhances the given {@code nonAnnotatedClass} to be an implementation of {@link Component}.
*
* @param clazz the {@link Class} to enhance to implement {@link Component}.
* @return the enhanced class, or the given {@code clazz} if it was already annotated.
* @throws UnsupportedOperationException if the given {@code clazz} is <b>not</b> annotated and is declared as {@code final}.
*/
public static <T, A extends Component> Class<A> addAnnotationsToClass(Class<T> clazz) {
if (Component.class.isAssignableFrom(clazz) && asList(clazz.getMethods()).stream().anyMatch(m -> "getAnnotations".equals(m.getName()) && !m.isDefault())) {
return (Class<A>) clazz;
}
if (isFinal(clazz.getModifiers())) {
throw new UnsupportedOperationException("Class '" + clazz.getName() + "' must either not be final or implement '" + Component.class.getName() + "'");
}
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(new Class[] { DynamicallyComponent.class });
enhancer.setSuperclass(clazz);
ComponentInterceptor annotatedObjectInvocationHandler = new ComponentInterceptor(MANAGED_METHODS);
CallbackHelper callbackHelper = new CallbackHelper(clazz, new Class[] { DynamicallyComponent.class }) {
@Override
protected Object getCallback(Method method) {
if (MANAGED_METHODS.contains(method) || annotatedObjectInvocationHandler.getOverridingMethods().containsKey(method)) {
return annotatedObjectInvocationHandler;
} else {
Optional<Method> overridingMethod = MANAGED_METHODS.stream().filter(m -> m.getName().equals(method.getName()) && Arrays.equals(m.getParameterTypes(), method.getParameterTypes())).findFirst();
if (overridingMethod.isPresent()) {
annotatedObjectInvocationHandler.getOverridingMethods().put(method, overridingMethod.get());
return annotatedObjectInvocationHandler;
} else {
return NoOp.INSTANCE;
}
}
}
};
enhancer.setCallbackTypes(callbackHelper.getCallbackTypes());
enhancer.setCallbackFilter(callbackHelper);
if (Enhancer.class.getClassLoader() != clazz.getClassLoader()) {
enhancer.setClassLoader(new CompositeClassLoader(AnnotatedObjectInvocationHandler.class.getClassLoader(), clazz.getClassLoader()));
enhancer.setUseCache(false);
}
Class<A> annotatedClass = enhancer.createClass();
registerStaticCallbacks(annotatedClass, callbackHelper.getCallbacks());
return annotatedClass;
}
use of org.mule.runtime.core.internal.util.CompositeClassLoader in project mule by mulesoft.
the class DefaultConnectionProviderObjectBuilder method applyExtensionClassLoaderProxy.
/**
* Wraps the {@link ConnectionProvider} inside of a dynamic proxy which changes the current {@link ClassLoader} to the the
* extension's {@link ClassLoader} when executing any method of this wrapped {@link ConnectionProvider}
* <p>
* This ensures that every time that the {@link ConnectionProvider} is used, it will work in the correct classloader.
* <p>
* Although if the {@link ConnectionProvider} is created with the correct classloader and then used with an incorrect one this
* may work, due that static class references were loaded correctly, logic loading class in a dynamic way will fail.
*
* @param provider The {@link ConnectionProvider} to wrap
* @return The wrapped {@link ConnectionProvider}
*/
private ConnectionProvider<C> applyExtensionClassLoaderProxy(ConnectionProvider provider) {
Enhancer enhancer = new Enhancer();
ClassLoader classLoader = getClassLoader(extensionModel);
Class[] proxyInterfaces = getProxyInterfaces(provider);
enhancer.setInterfaces(proxyInterfaces);
MethodInterceptor returnProviderInterceptor = (obj, method, args, proxy) -> provider;
MethodInterceptor invokerInterceptor = (obj, method, args, proxy) -> {
Reference<Object> resultReference = new Reference<>();
Reference<Throwable> errorReference = new Reference<>();
withContextClassLoader(classLoader, () -> {
try {
resultReference.set(method.invoke(provider, args));
} catch (InvocationTargetException e) {
errorReference.set(e.getTargetException());
} catch (Throwable t) {
errorReference.set(t);
}
});
if (errorReference.get() != null) {
throw errorReference.get();
} else {
return resultReference.get();
}
};
CallbackHelper callbackHelper = new CallbackHelper(Object.class, proxyInterfaces) {
@Override
protected Object getCallback(Method method) {
if (method.getDeclaringClass().equals(HasDelegate.class) && method.getName().equals("getDelegate")) {
return returnProviderInterceptor;
} else {
return invokerInterceptor;
}
}
};
enhancer.setCallbackTypes(callbackHelper.getCallbackTypes());
enhancer.setCallbackFilter(callbackHelper);
if (Enhancer.class.getClassLoader() != classLoader) {
enhancer.setClassLoader(new CompositeClassLoader(DefaultConnectionProviderObjectBuilder.class.getClassLoader(), classLoader));
enhancer.setUseCache(false);
}
Class<ConnectionProvider<C>> proxyClass = enhancer.createClass();
registerStaticCallbacks(proxyClass, callbackHelper.getCallbacks());
try {
return proxyClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new MuleRuntimeException(e);
}
}
use of org.mule.runtime.core.internal.util.CompositeClassLoader in project mule by mulesoft.
the class ObjectFactoryClassRepository method getObjectFactoryDynamicClass.
private Class<ObjectFactory> getObjectFactoryDynamicClass(final ComponentBuildingDefinition componentBuildingDefinition, final Class objectFactoryType, final Class createdObjectType, final Supplier<Boolean> isLazyInitFunction, final Optional<Consumer<Object>> instancePostCreationFunction) {
/*
* We need this to allow spring create the object using a FactoryBean but using the object factory setters and getters so we
* create as FactoryBean a dynamic class that will have the same attributes and methods as the ObjectFactory that the user
* defined. This way our API does not expose spring specific classes.
*/
Enhancer enhancer = new Enhancer();
// Use SmartFactoryBean since it's the only way to force spring to pre-instantiate FactoryBean for singletons
enhancer.setInterfaces(new Class[] { SmartFactoryBean.class });
enhancer.setSuperclass(objectFactoryType);
enhancer.setCallbackType(MethodInterceptor.class);
if (SmartFactoryBean.class.getClassLoader() != objectFactoryType.getClassLoader()) {
// CGLIB needs access to both the spring interface and the extended factory class.
// If the factory class is defined in a plugin, its classloader has to be passed.
enhancer.setClassLoader(new CompositeClassLoader(ObjectFactoryClassRepository.class.getClassLoader(), objectFactoryType.getClassLoader()));
}
// The use of the CGLIB cache is turned off when a post creation function is passed as argument in order to
// enrich the created proxy with properties. This is only to enable injecting properties in components
// from the compatibility module.
// Setting this to false will generate an excessive amount of different proxy classes loaded by the container CL
// that will end up in Metaspace OOM.
enhancer.setUseCache(!instancePostCreationFunction.isPresent());
Class<ObjectFactory> factoryBeanClass = enhancer.createClass();
registerStaticCallbacks(factoryBeanClass, new Callback[] { (MethodInterceptor) (obj, method, args, proxy) -> {
final boolean eager = !isLazyInitFunction.get();
if (method.getName().equals("isSingleton")) {
return !componentBuildingDefinition.isPrototype();
}
if (method.getName().equals("getObjectType") && !ObjectTypeProvider.class.isAssignableFrom(obj.getClass())) {
return createdObjectType;
}
if (method.getName().equals("getObject")) {
Object createdInstance = proxy.invokeSuper(obj, args);
instancePostCreationFunction.ifPresent(consumer -> consumer.accept(createdInstance));
return createdInstance;
}
if (method.getName().equals("isPrototype")) {
return componentBuildingDefinition.isPrototype();
}
if (method.getName().equals("isEagerInit")) {
return eager;
}
return proxy.invokeSuper(obj, args);
} });
return factoryBeanClass;
}
Aggregations