Support a DynamicOptions.ClassNameProvider
The new DynamicOptions.ClassNameProvider class allows the registering of DynamicOptions by class name. By using the class name, class loading can be deferred until classes are needed, allowing classes to be only loaded via the classloader of the running command. This classloading delay is important to help ensure that there is only one version of the class ever loaded when using cross plugin DynamicOptions. Direct registering of DynamicBeans is still supported (it is easier to use for extending core, or same plugin commands, when not crossing classloader boundaries). To ensure mutual exclusion of a command's bindings per plugin, the new DynamicOptions.ClassNameProvider extends the DynamicBean interface. When using the DynamicOptions.ClassNameProvider, any Options defined directly on it will be ignored since it is expected that the classname returned by the getClassName() will instead provide the options. Change-Id: I19a3de83dec40ea8eff2df8f9977c44729616581
This commit is contained in:
@@ -49,6 +49,33 @@ public class DynamicOptions {
|
||||
*/
|
||||
public interface DynamicBean {}
|
||||
|
||||
/**
|
||||
* To provide additional options to a command in another classloader, bind a ClassNameProvider
|
||||
* which provides the name of your DynamicBean in the other classLoader.
|
||||
*
|
||||
* <p>Do this by binding to just the name of the command you are going to bind to so that your
|
||||
* classLoader does not load the command's class which likely is not in your classpath. To ensure
|
||||
* that the command's class is not in your classpath, you can exclude it during your build.
|
||||
*
|
||||
* <p>For example:
|
||||
*
|
||||
* <pre>
|
||||
* bind(com.google.gerrit.server.DynamicOptions.DynamicBean.class)
|
||||
* .annotatedWith(Exports.named( "com.google.gerrit.plugins.otherplugin.command"))
|
||||
* .to(MyOptionsClassNameProvider.class);
|
||||
*
|
||||
* static class MyOptionsClassNameProvider implements DynamicOptions.ClassNameProvider {
|
||||
* @Override
|
||||
* public String getClassName() {
|
||||
* return "com.googlesource.gerrit.plugins.myplugin.CommandOptions";
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public interface ClassNameProvider extends DynamicBean {
|
||||
String getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this if your DynamicBean needs an opportunity to act on the Bean directly before or
|
||||
* after argument parsing.
|
||||
@@ -118,21 +145,32 @@ public class DynamicOptions {
|
||||
public DynamicBean getDynamicBean(Object bean, DynamicBean dynamicBean) {
|
||||
ClassLoader coreCl = getClass().getClassLoader();
|
||||
ClassLoader beanCl = bean.getClass().getClassLoader();
|
||||
|
||||
ClassLoader loader = beanCl;
|
||||
if (beanCl != coreCl) { // bean from a plugin?
|
||||
ClassLoader dynamicBeanCl = dynamicBean.getClass().getClassLoader();
|
||||
if (beanCl != dynamicBeanCl) { // in a different plugin?
|
||||
ClassLoader mergedCL = new DelegatingClassLoader(beanCl, dynamicBeanCl);
|
||||
try {
|
||||
return injector
|
||||
.createChildInjector()
|
||||
.getInstance(
|
||||
(Class<DynamicOptions.DynamicBean>)
|
||||
mergedCL.loadClass(dynamicBean.getClass().getCanonicalName()));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
loader = new DelegatingClassLoader(beanCl, dynamicBeanCl);
|
||||
}
|
||||
}
|
||||
|
||||
String className = null;
|
||||
if (dynamicBean instanceof ClassNameProvider) {
|
||||
className = ((ClassNameProvider) dynamicBean).getClassName();
|
||||
} else if (loader != beanCl) { // in a different plugin?
|
||||
className = dynamicBean.getClass().getCanonicalName();
|
||||
}
|
||||
|
||||
if (className != null) {
|
||||
try {
|
||||
return injector
|
||||
.createChildInjector()
|
||||
.getInstance((Class<DynamicOptions.DynamicBean>) loader.loadClass(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return dynamicBean;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user