KBeans
KBean is the central concept of the execution engine. KBeans are classes with declared executable methods.
There is only one KBean instance per KBean class in any given Jeka base directory.
KBean classes share the following characteristics:
- They extend the
KBean
class. - They may declare
public void
methods without arguments. All these methods can be invoked from the command line. - They may declare
public
fields (also known as KBean properties). These field values can be injected from the command line.
Additionally, they can have non-public fields annotated with@JkDoc
. - They must provide a no-argument constructor.
- They may override the
init()
method. - They must be instantiated by the execution engine and not by user code.
Simple Example¶
The following KBeans expose the cleanPublish
method, which delegates the creation of JAR files to the project
KBean.
ProjectKBean
is available on the Jeka classpath as it is part of the standard KBeans bundled in the JeKa distribution.
import dev.jeka.core.api.project.JkProject;
@JkDoc("A simple example to illustrate KBean concept.")
public class SimpleJkBean extends KBean {
final ProjectKBean projectKBean = load(ProjectKBean.class); // Instantiate KBean or return singleton instance.
@Override
protected void init() { // When init() is invoked, projectKBean field instances has already been injected.
projectKBean.project.flatFacade.compileDependencies
.add("com.google.guava:guava:30.0-jre")
.add("com.sun.jersey:jersey-server:1.19.4");
projectKBean.project.flatFacade.testDependencies
.add("org.junit.jupiter:junit-jupiter:5.8.1");
}
@JkDoc("Clean, compile, test, create jar files, and publish them.")
public void cleanPublish() {
projectKBean.cleanPack();
projectKBean.publishLocal();
}
}
KBean Methods¶
A KBean method is a specific method defined in a KBean class, designed to be executable from the command line interface. For successful recognition as a command, the method must adhere to the following criteria:
- It must be designated as
public
. - It must be an instance method, not static or abstract.
- It must not require any arguments upon invocation.
- It must not return any value, as indicated by a
void
return type.
KBean Attributes¶
A KBean attribute is a public
instance field of a KBean class. Its value can be injected from the command line or from a property file.
Additionally, it can be a non-public field annotated with @JkDoc
.
Attributes can be annotated with @JkInjectProperty("my.prop.name")
to inject the value of a property into the field.
We can also inject value using *jeka.properties
For more details on field accepted types, see the dev.jeka.core.tool.FieldInjector#parse
method.
KBean attributes can also represent nested composite objects. See the example in the ProjectKBean#pack
field.
Naming KBeans¶
To be referenced conveniently, KBeans can be identified by specific names. For any given KBean class, the accepted names are:
- Fully qualified class name.
- Uncapitalized simple class name (e.g.,
myBuild
matchesorg.example.MyBuild
). - Uncapitalized simple class name without the
KBean
suffix (e.g.,project
matchesdev.jeka.core.tool.builtin.project.ProjectKBean
).
Tip
Execute jeka
at the root of a project to display the KBeans available on the Jeka classpath.
Document KBeans¶
KBean classes, methods, and attributes can be annotated with the @JkDoc
annotation to provide self-documentation.
The text provided in these annotations is displayed when running the command:
jeka <kbeanName>: --doc
Invoke KBeans¶
From the Command Line¶
KBean methods can be executed directly from the command line using the syntax:
jeka <kbeanName>: [methodName...] [attributeName=xxx...]
Example: jeka project: info pack tests.fork=false pack.jarType=FAT jacoco: sonarqube: run
You can call multiple methods and set multiple attributes in a single command.
From IntelliJ Jeka Plugin¶
The IntelliJ Jeka Plugin enables invoking KBean methods directly from the IDE, either from the code editor or the project explorer tool window.
From a Plain IDE Setup¶
KBean methods can also be launched or debugged in an IDE by invoking the dev.jeka.core.tool.Main
method and passing the corresponding command-line arguments.
Example:
Invoking the dev.jeka.core.tool.Main
method with arguments project:
and compile
will instantiate the ProjectKBean
class and invoke its compile
method.
Warning
Ensure that the main method is launched with the module directory set as the working directory.
In IntelliJ, the default working directory is the project directory, which may cause issues.
To update IntelliJ defaults:
- Navigate to Run | Edit Configurations... | Application | Working Directory
- Set the value to $MODULE_DIR$
.
Default KBean¶
The [kbeanName] prefix is optional and defaults to:
- The KBean specified by the
jeka.default.kbean
property (if set). - Otherwise, the first KBean found in the jeka-src directory, ordered alphabetically by fully qualified class name.
Example: jeka doSomething aProperty=xxxx
invokes the doSomething
method of the default KBean.
Use :
to explicitly reference the default KBean and avoid ambiguity.
Example: jeka : --doc
shows the default KBean's documentation, while jeka --doc
displays overall documentation.
KBean Collaboration¶
KBeans can interact with one another by declaring dependencies using the KBean#load(MyBean.class)
method, as shown in the simple example.
Alternatively, you can use the KBean#find(MyKBean.class)
method, which returns an Optional<KBean>
containing the instance only if it already exists in the context.
When a KBean depends on another, it is best practice to declare the dependency as an instance field in the dependent KBean. This approach has several benefits:
- The dependency is explicitly documented in the auto-generated documentation.
- It is visible in IDE tools, making the relationship clear.
Lifecycle¶
This diagram shows how KBean instances are created or retrieved.
sequenceDiagram
participant EE as Execution Engine or user code
participant RB as Run Base
participant KB as KBean
participant OKB as Other KBeans
EE->>RB: Load KBean
RB->>RB: Find if singleton already exists
RB-->>EE: Return the singleton if found
RB->>KB: new
KB->>KB: Setup current base directory
KB-->>RB:
RB->>RB: Register Singleton
RB->>RB: Consume the singleton by the @JkPreInitKBean methods.
RB->>KB: Inject properties (e.g. -D@project.version=0.1 or @project.moduleId=ac.me:foo)
RB->>KB: Inject command-line values (e.g. project: version=0.1)
RB->>KB: Invoke init() method
KB->>KB: Specific KBean initialisation code (e.g. may be nothing)
KB-->> OKB: May load or call other KBans
KB-->>RB:
RB-->>EE:
classDiagram
class JkRunBase {
+Path baseDir
+KBean initKBean
+KBean defaultKBean
+JkProperties properties
+List dependencies
+KBean load()
+KBean find()
+List getKBeans()
}
class KBean {
+JkRunbase runbase
}
JkRunBase "1" <--> "0..*" KBean
JkRunBase --> "0..*" BaseDir: Imported Base Dirs (multi-modules)
note for JkRunBase "There is only one JkRunBase per base folder.<br/>The base folder is the project root.<br/>In multi-module projects, usually one JkRunBase exists per module."
note for BaseDir "This class doesn’t exist. It represents the base directory <br/>of another runbase in a multi-module project."
Multi-Project setup¶
In multi-project scenarios, it is common for a KBean in one project to access a KBean instance from another project. This can be achieved in a statically typed manner:
- In the master KBean, declare a field of type
KBean
(e.g.,KBean importedBuild;
). This field does not need to be public. - Annotate the field, by specifying the relative path of the imported project (e.g.,
@JkInjectRunbase("../anotherModule")
). - Run the command
jeka intellij: iml
orjeka eclipse: files
to refresh project metadata. - Change the declared field type from
KBean
to the concrete type of the imported KBean. - The master KBean can now access the imported KBean in a type-safe manner.
- For an example, see this implementation.
Tip
Ensure that the imported KBean uses KBean#getBaseDir
for handling file paths. This practice ensures safe execution from any working directory.