diff --git a/core/pom.xml b/core/pom.xml
index 7ce3c78662c44561395112c32ad263bb3c05b6ea..054a782e4c28b092afea4031cb0f4793df6af9e7 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -42,7 +42,7 @@ THE SOFTWARE.
true
- 1.218
+ 1.220
2.5.6.SEC03
1.8.9
diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java
index e0cc80c5ea3ba5b60b717d6a6a15a8a0290ea9fc..15df186793e3cde2137263a5ab7d3c60e540c978 100644
--- a/core/src/main/java/hudson/model/Descriptor.java
+++ b/core/src/main/java/hudson/model/Descriptor.java
@@ -29,6 +29,7 @@ import hudson.RelativePath;
import hudson.XmlFile;
import hudson.BulkChange;
import hudson.Util;
+import hudson.init.Initializer;
import hudson.model.listeners.SaveableListener;
import hudson.util.FormApply;
import hudson.util.FormValidation.CheckMethod;
@@ -62,6 +63,7 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -985,4 +987,77 @@ public abstract class Descriptor> implements Saveable {
public static final class Self {}
protected static Class self() { return Self.class; }
+
+ /**
+ * Register a global {@link BindInterceptor} that uses {@link Descriptor#newInstance(StaplerRequest, JSONObject)}
+ * for instantiation
+ */
+ @Initializer
+ public static void initGlobalBindInterceptor() {
+ boolean newInstance = WebApp.get(Jenkins.getInstance().servletContext).bindInterceptors.add(new BindInterceptor() {
+ final class Input {
+ final Class type;
+ final JSONObject json;
+
+ private Input(Class type, JSONObject json) {
+ this.type = type;
+ this.json = json;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Input rhs = (Input) o;
+ return json==rhs.json && type==rhs.type;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return 31*type.hashCode() + json.hashCode();
+ }
+ }
+
+ private final ThreadLocal> inputs = new ThreadLocal>() {
+ protected Stack initialValue() {
+ return new Stack();
+ }
+ };
+
+ @Override
+ public Object instantiate(Class actualType, JSONObject json) {
+ if (Describable.class.isAssignableFrom(actualType)) {
+ Descriptor d = Jenkins.getInstance().getDescriptor(actualType);
+ if (d != null) {
+ try {
+ // only when Descriptor.newInstance is overridden
+ Method m = d.getClass().getMethod("newInstance", StaplerRequest.class, JSONObject.class);
+ if (m.getDeclaringClass() != Descriptor.class) {
+ Input newFrame = new Input(actualType,json);
+ if (!inputs.get().contains(newFrame)) {
+ // prevent infinite recursion in case Descriptor.newInstance calls right back into
+ // bindJSON
+ inputs.get().push(newFrame);
+ try {
+ StaplerRequest req = Stapler.getCurrentRequest();
+ if (req != null)
+ return d.newInstance(req, json);
+ } finally {
+ inputs.get().pop();
+ }
+ }
+ }
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e); // this can't happen because Descriptor defines such a method
+ } catch (FormException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ }
+ return DEFAULT;
+ }
+ });
+ }
}
diff --git a/test/src/test/java/hudson/model/DescriptorTest.java b/test/src/test/java/hudson/model/DescriptorTest.java
index b8c0c5bc38bea692a022f85af306370fbb87bef7..8ce832e8598f999e43eda296cadb3202989f96ae 100644
--- a/test/src/test/java/hudson/model/DescriptorTest.java
+++ b/test/src/test/java/hudson/model/DescriptorTest.java
@@ -27,10 +27,17 @@ package hudson.model;
import hudson.model.Descriptor.PropertyType;
import hudson.tasks.Shell;
import static org.junit.Assert.*;
+
+import net.sf.json.JSONObject;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.JenkinsRule;
+import org.jvnet.hudson.test.TestExtension;
+import org.kohsuke.stapler.Stapler;
+import org.kohsuke.stapler.StaplerRequest;
+
+import java.util.concurrent.Callable;
public class DescriptorTest {
@@ -51,4 +58,42 @@ public class DescriptorTest {
}
}
+ /**
+ * Make sure Descriptor.newInstance gets invoked.
+ */
+ @Bug(18629) @Test
+ public void callDescriptor_newInstance() throws Exception {
+ rule.executeOnServer(new Callable