Inheritance is not working inside of my pipelines or shared libraries

Article ID:360039668972
2 minute readKnowledge base

Issue

  • I am trying to code inheritance inside of my shared libraries and it does not seem to be working

  • I am trying to define sub-classes of other classes inside of my shared libraries and it keeps failing

Definition

Inheritance can be defined as the process where one class acquires the properties (methods and fields) of another. With the use of inheritance the information is made manageable in a hierarchical order. This allows you to extend a single class and then add methods to it for use inside of further Groovy scripts. In Groovy this is done by using the extends keyword to extend an existing class.

Why it does not work

In order to allow Pipelines to be resumed, Pipeline uses a custom Groovy compiler that allows the execution state of the Groovy program to be saved, and then resumed from the saved state (via a continuation-passing-style (CPS) transformation). This custom compiler works correctly in many cases, but some Groovy features, such as inheritance, are not implemented correctly, and have various bugs, or require precise use of the @NonCPS annotation in order to make things work correctly. It is those edge cases that are difficult to track down and therefore the use of inheritance is not recommended.

Reasoning

There are three main reasons that inheritance should not be used inside of pipelines:

  1. It goes against the best practices guide where Groovy code is designed to be used as "glue" to put separate pipeline steps together. This gets into much more complex Groovy situations than what the pipeline version of Groovy is designed for.

  2. If you extend Java classes in your Pipelines, it is extremely easy to introduce severe memory leaks on your Jenkins controller. It can also be an indication that you are trying to access or work with internal Jenkins APIs directly from a Pipeline, which is strongly discouraged. See PR #102 to Pipeline: API Plugin as an example of a problem that was encountered in a real pipeline, and which is now handled specially by Pipeline internals to avoid memory leaks, but there are many other ways to cause similar issues that cannot be fixed by Pipeline or Jenkins itself.

  3. The number of edge cases where inheritance would break a pipeline execution is potentially numerous. Additionally those edge cases could change per-build and be extremely hard to reproduce/fix. Having unreliable builds which randomly fail is never an experience desired for pipelines.