diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/DynamicContext.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/DynamicContext.java index 61a4d63..67df4c2 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/DynamicContext.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/DynamicContext.java @@ -89,9 +89,17 @@ abstract class Typed implements DynamicContext { */ protected abstract @CheckForNull T get(DelegatedContext context) throws IOException, InterruptedException; - @Override public final T get(Class key, DelegatedContext context) throws IOException, InterruptedException { - if (key.isAssignableFrom(type())) { + @Override public final U get(Class key, DelegatedContext context) throws IOException, InterruptedException { + Class type = type(); + if (key.isAssignableFrom(type)) { return key.cast(get(context)); + } else if (type.isAssignableFrom(key)) { + T t = get(context); + if (key.isInstance(t)) { + return key.cast(t); + } else { + return null; + } } else { return null; } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/DynamicContextTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/DynamicContextTest.java new file mode 100644 index 0000000..8619b2d --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/DynamicContextTest.java @@ -0,0 +1,57 @@ +/* + * The MIT License + * + * Copyright 2021 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.jenkinsci.plugins.workflow.steps; + +import java.io.IOException; +import org.junit.Test; +import static org.junit.Assert.*; + +public class DynamicContextTest { + + @Test public void subclassing() throws Exception { + class Super {} + class Sub extends Super {} + class Sub2 extends Super {} + DynamicContext.DelegatedContext nullContext = new DynamicContext.DelegatedContext() { + @Override public T get(Class key) throws IOException, InterruptedException { + return null; + } + }; + class Dyn extends DynamicContext.Typed { + @Override protected Class type() { + return Super.class; + } + @Override protected Super get(DelegatedContext context) { + return new Sub(); + } + } + DynamicContext ctx = new Dyn(); + assertNotNull("can look up via supertype", ctx.get(Super.class, nullContext)); + assertNotNull("can look up via subtype", ctx.get(Sub.class, nullContext)); + assertNull("but not via a mismatched subtype", ctx.get(Sub2.class, nullContext)); + assertNull("nor via an unrelated supertype", ctx.get(Runnable.class, nullContext)); + } + +}