Jawk 6.4.00
-
Home
- Extensions
Writing Extensions
Modern Jawk extensions are small Java classes that expose AWK-callable functions through annotations. In most cases, you should extend AbstractExtension, annotate Java methods with @JawkFunction, and let Jawk build the function map automatically.
Prefer annotations and AbstractExtension by default. Drop to custom dispatch only when you genuinely need dynamic keyword handling or a non-standard function map.
Prefer AbstractExtension
AbstractExtension[1] already handles common extension plumbing:
- it stores the
VariableManager,JRT, andAwkSettings - it scans the extension class for annotated functions
- it builds the immutable keyword-to-function map returned to the parser and runtime
That means most extensions do not need to implement getExtensionFunctions() themselves.
Expose Functions with @JawkFunction
Annotate each Java method you want Jawk to expose:
@JawkFunction("Repeat")
public String repeat(Number count, String value) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < count.intValue(); i++) {
result.append(value);
}
return result.toString();
}
The annotation value is the AWK function name seen by the script.
Mark Assoc Array Parameters with @JawkAssocArray
Use @JawkAssocArray on parameters that must receive an associative array. Annotated parameters should be declared as Map, which keeps the extension API decoupled from the concrete AssocArray implementation Jawk provides at runtime. Do not use concrete map classes such as HashMap or TreeMap, because Jawk passes AssocArray instances:
@JawkFunction("AssocSize")
public int assocSize(@JawkAssocArray Map<Object, Object> array) {
return array.keySet().size();
}
That metadata lets Jawk validate array-vs-scalar usage more accurately.
Registering Extensions
There are two distinct registration paths:
- Java embedding: pass the extension instance directly to
new Awk(...) - CLI usage and
--list-ext: register an instance withExtensionRegistry
If you want the extension to show up through the registry, register it explicitly:
public final class SampleExtension extends AbstractExtension {
static {
ExtensionRegistry.register("sample", new SampleExtension());
}
@Override
public String getExtensionName() {
return "sample";
}
@JawkFunction("Repeat")
public String repeat(Number count, String value) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < count.intValue(); i++) {
result.append(value);
}
return result.toString();
}
@JawkFunction("AssocSize")
public int assocSize(@JawkAssocArray Map<Object, Object> array) {
return array.keySet().size();
}
}
When You Still Need Custom Dispatch
The annotation path is not mandatory. You may still implement JawkExtension directly, or override the default function-map behavior, when:
- function names are determined dynamically
- the extension wants to expose different function sets at runtime
- you need a highly customized mapping layer
That is the exception, not the default.
Minimal End-to-End Example
Use the extension directly from Java:
Awk awk = new Awk(new SampleExtension());
Object value = awk.eval("Repeat(3, \"ha\")");
// value = "hahaha"
Or expose it to the CLI after placing the class on the JVM classpath and registering it:
$ java -cp my-extension.jar -jar jawk-6.4.00-standalone.jar --list-ext
SampleExtension - com.company.my.SampleExtension
sample - com.company.my.SampleExtension
io.jawk.ext.StdinExtension - io.jawk.ext.StdinExtension
stdin - io.jawk.ext.StdinExtension
Stdin Support - io.jawk.ext.StdinExtension
$ java -cp my-extension.jar -jar jawk-6.4.00-standalone.jar -l sample 'BEGIN { print Repeat(3, "ha") }'
hahaha
See Also
- [1] apidocs/io/jawk/ext/AbstractExtension.html
- [2] extensions.html
- [3] java.html
