Enkan provides a set of development tools that enable rapid iterative development.
The enkan-devel module includes class reloading, REPL compilation, automatic reset,
error visualization, and request tracing.
Enkan supports hot-reloading of Java classes without restarting the JVM.
This is achieved by replacing the ClassLoader each time the application resets.
ConfigurationLoader is a custom ClassLoader that identifies reloadable classpath directories.
A directory is considered reloadable if it contains META-INF/reload.xml.
When the application starts, ApplicationComponent creates a new ConfigurationLoader
and loads the ApplicationFactory class through it.
When the application resets (/reset), the old ConfigurationLoader is discarded
and a new one is created. Since a fresh ClassLoader reads .class files from disk,
any recompiled classes are picked up automatically.
Place an empty META-INF/reload.xml file in your resources directory:
src/main/resources/META-INF/reload.xml
This marks the corresponding output directory (e.g., target/classes) as a reloading target.
Only classes in directories containing this marker file will be reloaded.
META-INF/reload.xmlClasses from JAR dependencies are not reloaded. They are delegated to the parent ClassLoader.
The /autoreset command watches compiled class files for changes and automatically
resets the application when a modification is detected.
enkan> /autoreset
Start to watch modification an application.
Once enabled, whenever a .class file changes in a reloadable directory,
the system automatically calls stop() followed by start(), reloading all classes.
ClassWatcher uses Java NIO WatchService to monitor reloadable directories.
It registers watches recursively on all subdirectories and detects ENTRY_CREATE
and ENTRY_MODIFY events. New subdirectories created after watching starts are
automatically registered.
/start/autoreset/compile) compiles the sources.class filesThe /compile command triggers project compilation from the REPL.
enkan> /compile
MavenCompiler invokes Maven’s compile goal using the Maven Invoker API.
It reads MAVEN_HOME or M2_HOME environment variable (falls back to /opt/maven).
To use Gradle instead of Maven, configure DevelCommandRegister with a GradleCompiler:
DevelCommandRegister devel = new DevelCommandRegister(new GradleCompiler());
GradleCompiler uses the Gradle Tooling API to invoke the compileJava task.
By default, it downloads Gradle 8.14.4 automatically. You can override this by setting
the GRADLE_HOME environment variable to use a local installation.
The enkan-devel module provides middlewares designed for use during development.
These should not be included in production deployments.
<dependency>
<groupId>net.unit8.enkan</groupId>
<artifactId>enkan-devel</artifactId>
</dependency>
Catches exceptions and renders detailed HTML error pages with stack traces.
app.use(new StacktraceMiddleware<>());
It handles different exception types with specialized pages:
Records HTTP request/response traces and provides a web UI to inspect them.
app.use(new TraceWebMiddleware<>());
Access the trace UI at http://localhost:3000/x-enkan/requests to see:
The mount path and store size are configurable:
| Name | Type | Description | Default |
|---|---|---|---|
| mountPath | String | URL path for trace UI | /x-enkan/requests |
| storeSize | long | Maximum number of stored requests | 100 |
Renders HTTP status cat images for error responses. Useful for quickly identifying
status codes during development.
app.use(new HttpStatusCatMiddleware());
Development commands are registered via DevelCommandRegister when bootstrapping the REPL:
PseudoRepl repl = new PseudoRepl(MySystemFactory.class.getName());
ReplBoot.start(repl,
new KotowariCommandRegister(),
new DevelCommandRegister(),
new MetricsCommandRegister());
DevelCommandRegister registers the following commands:
| Command | Description |
|---|---|
| /autoreset | Watch class files and reset on change |
| /compile | Compile project using Maven or Gradle |