From c424a4c301f452c57eee9f784014a61c02a0d852 Mon Sep 17 00:00:00 2001 From: Jason Dillon Date: Sat, 24 Jul 2010 19:24:08 -0700 Subject: [PATCH 1/2] Introduce DescribableFactoryDelegate, exposed by PluginStrategy. ClassPluginStrategy.DefaultDescribableFactoryDelegate performs exactly what Descriptor.newInstance(StaplerRequest,JSONObject). --- .../main/java/hudson/ClassicPluginStrategy.java | 62 ++++++++++++++++++++ core/src/main/java/hudson/PluginStrategy.java | 8 +++ .../hudson/model/DescribableFactoryDelegate.java | 15 +++++ core/src/main/java/hudson/model/Descriptor.java | 39 +++++------- 4 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 core/src/main/java/hudson/model/DescribableFactoryDelegate.java diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 8df5bab..8b69e09 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -24,6 +24,9 @@ package hudson; import hudson.PluginWrapper.Dependency; +import hudson.model.Describable; +import hudson.model.DescribableFactoryDelegate; +import hudson.model.Descriptor; import hudson.util.IOException2; import hudson.util.MaskingClassLoader; import hudson.util.VersionNumber; @@ -36,6 +39,8 @@ import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.Closeable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -49,11 +54,13 @@ import java.util.jar.Manifest; import java.util.jar.Attributes; import java.util.logging.Logger; +import net.sf.json.JSONObject; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.taskdefs.Expand; import org.apache.tools.ant.types.FileSet; +import org.kohsuke.stapler.StaplerRequest; public class ClassicPluginStrategy implements PluginStrategy { @@ -432,4 +439,59 @@ public class ClassicPluginStrategy implements PluginStrategy { } public static boolean useAntClassLoader = Boolean.getBoolean(ClassicPluginStrategy.class.getName()+".useAntClassLoader"); + + // + // DescribableFactoryDelegate + // + + /** + * @since 1.368 + */ + public static class DefaultDescribableFactoryDelegate + implements DescribableFactoryDelegate + { + public > T create(final Descriptor descriptor, final StaplerRequest req, final JSONObject data) + throws Exception + { + try { + Method m = descriptor.getClass().getMethod("newInstance", StaplerRequest.class); + + if (!Modifier.isAbstract(m.getDeclaringClass().getModifiers())) { + // this class overrides newInstance(StaplerRequest). + // maintain the backward compatible behavior + return descriptor.newInstance(req); + } + else { + if (req==null) { + // yes, req is supposed to be always non-null, but see the note above + return descriptor.getDescribableType().newInstance(); + } + + // new behavior as of 1.206 + return req.bindJSON(descriptor.getDescribableType(), data); + } + } + catch (NoSuchMethodException e) { + throw new AssertionError(e); // impossible + } + catch (InstantiationException e) { + throw new Error(e); + } + catch (IllegalAccessException e) { + throw new Error(e); + } + } + } + + private DescribableFactoryDelegate describableFactoryDelegate; + + /** + * @since 1.368 + */ + public DescribableFactoryDelegate getDescribableFactoryDelegate() { + if (describableFactoryDelegate == null) { + describableFactoryDelegate = new DefaultDescribableFactoryDelegate(); + } + return describableFactoryDelegate; + } } diff --git a/core/src/main/java/hudson/PluginStrategy.java b/core/src/main/java/hudson/PluginStrategy.java index 0fe0e72..db1ea6e 100644 --- a/core/src/main/java/hudson/PluginStrategy.java +++ b/core/src/main/java/hudson/PluginStrategy.java @@ -23,6 +23,8 @@ */ package hudson; +import hudson.model.DescribableFactoryDelegate; + import java.io.File; import java.io.IOException; @@ -63,4 +65,10 @@ public interface PluginStrategy extends ExtensionPoint { */ public abstract void initializeComponents(PluginWrapper plugin); + /** + * Returns the factory delegate used to construct new {@link hudson.model.Describable} instances. + * + * @since 1.368 + */ + DescribableFactoryDelegate getDescribableFactoryDelegate(); } \ No newline at end of file diff --git a/core/src/main/java/hudson/model/DescribableFactoryDelegate.java b/core/src/main/java/hudson/model/DescribableFactoryDelegate.java new file mode 100644 index 0000000..44c18a7 --- /dev/null +++ b/core/src/main/java/hudson/model/DescribableFactoryDelegate.java @@ -0,0 +1,15 @@ +package hudson.model; + +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; + +/** + * Allows {@link hudson.PluginStrategy} to control the behavior of {@link Descriptor#newInstance(StaplerRequest, JSONObject)}. + * + * @author Jason Dillon + * @since 1.368 + */ +public interface DescribableFactoryDelegate +{ + > T create(Descriptor descriptor, StaplerRequest req, JSONObject data) throws Exception; +} diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index 6afed9c..825cc4a 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -58,7 +58,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; @@ -237,6 +236,10 @@ public abstract class Descriptor> implements Saveable { } + public Class getDescribableType() { + return clazz; + } + /** * Human readable name of this kind of configurable object. */ @@ -414,6 +417,8 @@ public abstract class Descriptor> implements Saveable { throw new UnsupportedOperationException(getClass()+" should implement newInstance(StaplerRequest,JSONObject)"); } + private static DescribableFactoryDelegate describableFactoryDelegate; + /** * Creates a configured instance from the submitted form. * @@ -449,28 +454,18 @@ public abstract class Descriptor> implements Saveable { * @since 1.145 */ public T newInstance(StaplerRequest req, JSONObject formData) throws FormException { + // Ask the delegate to perform instance creation for us + if (describableFactoryDelegate == null) { + describableFactoryDelegate = Hudson.getInstance().getPluginManager().getPluginStrategy().getDescribableFactoryDelegate(); + } try { - Method m = getClass().getMethod("newInstance", StaplerRequest.class); - - if(!Modifier.isAbstract(m.getDeclaringClass().getModifiers())) { - // this class overrides newInstance(StaplerRequest). - // maintain the backward compatible behavior - return newInstance(req); - } else { - if (req==null) { - // yes, req is supposed to be always non-null, but see the note above - return clazz.newInstance(); - } - - // new behavior as of 1.206 - return req.bindJSON(clazz,formData); - } - } catch (NoSuchMethodException e) { - throw new AssertionError(e); // impossible - } catch (InstantiationException e) { - throw new Error(e); - } catch (IllegalAccessException e) { - throw new Error(e); + return describableFactoryDelegate.create(this, req, formData); + } + catch (FormException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); } } -- 1.7.1.1