Java - concepts
Why Java matters here: Jenkins and all its plugins are written in Java. You rarely write Java day-to-day, but you read Java plugin source on GitHub to learn what DSL methods exist, what parameters they take, and how they work. Groovy runs on the JVM and can call any Java class directly.
Annotations - metadata on classes and methods
Annotations are markers (@Name) attached to classes, methods or fields.
They look like Python decorators but work differently - they’re passive
metadata, read later via reflection, rather than wrapping the target.
@Symbol("gitHubBranchDiscovery")
public static class DescriptorImpl extends SCMSourceTraitDescriptor { }
public @interface Symbol { String[] value(); } // declares the annotation
// read at runtime via reflection:
Symbol s = clazz.getAnnotation(Symbol.class);
if (s != null) { String name = s.value()[0]; }
This is exactly what the Job DSL plugin does - it scans installed plugins for
@DataBoundConstructor and @Symbol via reflection and auto-generates DSL
methods.
Annotation |
What it marks |
Who reads it |
|---|---|---|
|
constructor with required params |
Stapler (UI), Job DSL |
|
setter with optional param |
Stapler, Job DSL |
|
short name for a class |
Job DSL, Pipeline DSL |
|
overrides parent / outdated |
Java compiler (built-in) |
Interfaces, inheritance, generics
An interface defines methods a class must implement. In Jenkins,
Describable is the key one - a class that implements it can have DSL methods
generated for it.
public class BranchSource extends AbstractDescribableImpl<BranchSource> {
// extends = inherit from one parent class (single inheritance)
// implements = fulfill one or more interfaces
}
AbstractDescribableImpl is a convenience base that implements Describable
for you; most plugin classes extend it rather than implementing Describable
directly. The <T> generics syntax (like Python’s list[str] hints) is
a compile-time type constraint - when reading plugin code you can mostly ignore
it: AbstractDescribableImpl<BranchSource> just means “a Describable for
BranchSource”.
Access modifiers
Modifier |
Visible to |
|---|---|
|
everything |
|
same class + subclasses |
(none) |
same package only |
|
same class only |
In plugin source, public methods with @DataBoundConstructor /
@DataBoundSetter are the ones that become DSL methods; private fields are
the internal state they set.
Reading Java plugin source - what to look for
When checking whether a DSL method exists for a plugin class on GitHub:
Find the class - e.g.
BranchSource.javainjenkinsci/branch-api-plugin.Check
@DataBoundConstructor- its params become required DSL properties.Check
@DataBoundSetter- its methods become optional DSL properties.Check
@Symbolon theDescriptorImplinner class - that’s the DSL method name.Check
extends/implements- if it extendsAbstractDescribableImpl, the dynamic DSL can generate methods for it.