Repository navigation
Releases: janino-lts/janino
Release list
janino-3.1.20
JANINO-3.1.20
Fourteen fixes in the compiler, from the 3.1.x maintenance line (see "Release lines" in Compatibility), and JAR files
without the dummy signature. Upgrade if your code declares two local classes with the same name in one class, or
uses super.m() for a private or static method of the superclass: such code compiled, but used the wrong
class or failed at run time.
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.20</version>
</dependency>Fixed
Code that compiled, but did not run as written:
- #143: Two local classes with the same name in one class, or a
local class and a member class with the same name, got the same binary name, and only one class file was kept:
the code used the wrong class, or failed with aNoSuchMethodError. Now such a local class gets a number, like
withjavac(P$2L, orP$1Lnext to a member classL); the names of all other local classes are unchanged. - #136:
super.m()for aprivatemethod of the superclass
P, in a subclass ofPdeclared inP, failed at run time with aNoSuchMethodError. - #150:
super.s()for astaticmethod of the superclass
failed at run time with anIncompatibleClassChangeError;Outer.super.s()was an internal compiler error. - #160:
super.a(o, v)for a variable arity method that the
superclass implements from an interface compiled into a class that the JVM rejected (VerifyErroron Java 25,
IncompatibleClassChangeErroron older JVMs).
Code that was rejected or crashed the compiler, and now compiles like with javac:
- #127: An array of a primitive type as the only variable arity
argument of a parameterObject..., e.g.f(1, new int[] { 1, 2 })withf(Integer i, Object... a). - #134: Some invocations of overloaded methods or constructors
with anullargument (internal compiler error). - #147: Invocations of overloaded variable arity methods whose
parameter types are the leading parameter types of another (internal compiler error; now reported as ambiguous). - #156 and #169:
Invocations of variable arity methods, one of which is more specific, e.g.g(1, 2, 3)withg(int...)and
g(double...), were rejected as ambiguous. - #157:
super.f("a", "b")for a variable arity method
f(String...)was rejected,super.f()was an internal compiler error. - #138: An array type of a parameterized type, e.g.
List<Object>[], as the type of some local variables, of a cast or a type argument. - #133: A static method imported twice (internal compiler error
when it was invoked). - #153:
if (b) {}with a condition of typeBoolean. - #154: A
publicorprotectedmember of a class that is not
accessible, inherited through an accessible subclass, e.g.p.B.m()withpublic class B extends Aand a
package-private classA.
Unsigned JAR files
The JAR files are no longer signed with the dummy certificate that Janino has used since 2.5.7
(META-INF/DUMMY.SF, META-INF/DUMMY.DSA). Its key is public, so the signature proved nothing. Fat JARs no longer
need to exclude these files. The classes, the OSGi headers and the automatic module names are unchanged; the
artifacts on Maven Central are signed with PGP as before, and the GitHub release has SHA256SUMS.
Performance
Measured interleaved on JDK 25 (janino-benchmarks, with and without JIT, each with an A/A control):
- Against 3.1.19, the compile time is unchanged within the measurement error on all workloads, including the code
that Apache Spark generates for TPC-DS queries, and so is the memory that a compilation allocates (without JIT,
where it is deterministic: +0.0 to +0.1 %). The generated class files are byte-identical for all workloads. - Against 3.1.12, the last release of the original project: Janino's own sources compile 14 % faster without JIT
and with 14 to 16 % less memory; the code that Spark generates compiles equally fast with JIT, and without JIT
1.2 % faster and with 4.5 % less memory. Code with many nestedtry/finallystatements needs 20 to 26 % more
time and 16 to 17 % more memory, because the code that Janino generates for it since 3.1.14 is correct, but
larger.
See the benchmark README for the method.
Compatibility notes
- No code that compiled with 3.1.19 is rejected now.
- The class files change only for the invocations of #136, #150 and #160, which failed at run time, and for local
classes whose binary names collided (#143). For all workloads of the benchmarks, including Janino's own sources
and the code that Apache Spark generates for TPC-DS queries, the class files are the same as with 3.1.19, byte for
byte (see "Performance" above). - The test suites of Apache Calcite (all modules), Spark Catalyst (349 suites) and Apache Fory (all Java modules),
and about 4800 tests of the execution engine of Apache Drill, pass with this release as with the Janino that the
projects declare. - Java 8 or later is required. Janino is built with JDK 25 and tested on Java 8, 17, 21 and 25.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler, commons-compiler-jdk
(each with sources and Javadoc), commons-compiler-tests, and the POMs, including janino-parent.
Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.19
JANINO-3.1.19
Five fixes in the compiler, from the 3.1.x maintenance line (see "Release lines" in Compatibility). Upgrade if you
use qualified superclass method invocations (Outer.super.m()) in inner classes: since 3.1.16, such an invocation
in an inner class that extends Outer invoked the method on the wrong instance.
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.19</version>
</dependency>Fixed
- #110:
Outer.super.m()in an inner class that itself extendsOuter(also in a class nested in it, and in an anonymous
or local subclass ofOuter) invoked the superclass method on the instance of the inner class instead of the enclosing
instance. Since 3.1.16. - #97: An inner class whose superclass is an inner class that extends the enclosing class, e.g.
class R extends Qwith
class Q extends PinP, compiled into a class that the JVM rejected (VerifyError). - #87, the part that changes behavior: a
protectedmember type could not be used from a subclass of the enclosing
type in another package (IllegalAccessError); its class file now has the flagACC_PUBLIC, like withjavac. - #113: A conditional expression with a constant condition in the initializer of a
static finalfield,
e.g.static final int K = DEBUG ? 1 : 2;, was an internal compiler error; as an annotation element value,
@A(true ? 1 : 2), it was rejected, and so was@B(X || Y). - #96: Floating-point literals with a leading zero, e.g.
09.5,07e1or07f, were rejected. They compile now, except
with an underscore directly before the first digit8or9, e.g.0_9.5. Invalid octal literals such as09are reported
with the same messages as before.
Performance
Measured interleaved on JDK 25 (janino-benchmarks, with and without JIT, each with an A/A control):
- Against 3.1.18, the compile time is unchanged within the measurement error on all workloads, including the code
that Apache Spark generates for TPC-DS queries, and so is the memory that a compilation allocates (without JIT,
where it is deterministic: -0.1 to +0.1 %). The generated class files are byte-identical for all workloads. - Against 3.1.12, the last release of the original project: Janino's own sources compile 5 % faster with JIT (15 %
without) and with 14 to 16 % less memory; the code that Spark generates compiles equally fast with JIT, and without
JIT 1.8 % faster and with 4.6 % less memory. Code with many nestedtry/finallystatements needs 24 to 27 % more
time and 15 to 17 % more memory, because the code that Janino generates for it since 3.1.14 is correct, but larger.
See the benchmark README for the method.
Compatibility notes
- No code that compiled before is rejected now.
- The class files change only for
protectedmember types (one flag, #87), for the constructors of the #97 cases,
which the JVM rejected before, and for the invocations of #110. For all workloads of the benchmarks, including
Janino's own sources and the code that Apache Spark generates for TPC-DS queries, the class files are the same
as with 3.1.18, byte for byte (see "Performance" above). - The test suites of Apache Calcite (all modules) and of Spark Catalyst (349 suites) pass with this release as with
the Janino that the projects declare. - Java 8 or later is required. Janino is built with JDK 25 and tested on Java 8, 17, 21 and 25.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler, commons-compiler-jdk
(each with sources and Javadoc), commons-compiler-tests, and the POMs, including janino-parent.
Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.18
JANINO-3.1.18
The first release of the 3.1.x maintenance line (see "Release lines" in Compatibility). The compiler is unchanged: the generated class files are the same as with 3.1.17, byte for byte.
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.18</version>
</dependency>Fixed
- #76, in part:
ExpressionEvaluator.guessParameterNames()andScriptEvaluator.guessParameterNames()did
not find the names in the initializers of local variables and fields and in array initializers,
e.g.xinint y = x; return y;anda,binnew int[] { a, b }. They find them now.
AbstractTraverser, which does not descend into such initializers either, is public API and stays unchanged in the 3.1.x line.
Other changes
- The Javadoc JARs no longer contain the web fonts that the Javadoc tool of JDK 23 and later adds (about 4 MB per
JAR); the browser uses the fonts of the system instead. - Compatibility describes the two release lines and lists the API that Apache Calcite uses, next to that of Apache Spark;
DownstreamApiTestuses both exactly as the projects do.
Compatibility notes
- The compiler is unchanged. The class files are the same as with 3.1.17 for all workloads of the benchmarks,
including Janino's own sources and the code that Apache Spark generates for TPC-DS queries. guessParameterNames()now also returns a name that occurs only in an initializer; if such a name denotes a
field of the superclass of the script, it is guessed to be a parameter, like the same name in a statement.- The test suites of Apache Calcite (all modules) and of Spark Catalyst (349 suites) pass with this release as
with the Janino version that the projects declare. - Java 8 or later is required. Janino is built with JDK 25 and tested on Java 8, 17, 21 and 25.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler,
commons-compiler-jdk (each with sources and Javadoc), commons-compiler-tests, and the POMs, including
janino-parent. Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.17
JANINO-3.1.17
Local and anonymous classes can now access effectively final local variables (Java 8). Seven defects are fixed
that exist in 3.1.12 already. No code that compiled before is rejected now, and the generated class files of such
code are unchanged, with two small exceptions (see the compatibility notes).
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.17</version>
</dependency>New language feature
- #24: A local or anonymous class can access a local variable, a parameter, a
catchparameter or the variable of an
enhancedforstatement that is not declaredfinal, if the variable is effectively final (JLS 8.1.3); before, such an
access was rejected ("Cannot access non-final local variable"). JANINO applies a conservative rule: the variable has an
initializer, or is a parameter, and its name is not assigned, incremented or decremented anywhere in the enclosing
method; see JAVAC_DIFFERENCES.md, section 2, for the cases thatjavacaccepts and JANINO still rejects.
Fixed
- #58:
clone()of an array had the typeObjectinstead of the array type (JLS 10.7):int[] b = a.clone();was rejected,
anda.clone()[0]was an internal compiler error. - #60: A local class declaration with a modifier or an annotation (
final class L {},@A class L {}) was a syntax error. - #71: A subscript on an expression that is not an array was an internal compiler error when the expression was a method
or constructor argument, e.g.String.valueOf(o[0]). - #64: The resource variable of a try-with-resources statement,
try (R r = new R()) { ... }, was not accessible: neither
in the block, nor in the following resources, nor in an anonymous or local class in the block. - #59: A
protectedmember that an enclosing class inherits from a class in another package, accessed from an inner class,
compiled into a class that throws anIllegalAccessErroror fails to verify. Likejavac, JANINO now generates a synthetic
accessor method in the enclosing class. - #65, in part: A type in the
throwsclause of a method whose simple name consists of uppercase letters only (throws IOEXC)
was taken for a type parameter and ignored, so thecatchof such an exception was "unreachable", and theExceptions
attribute was incomplete. For compatibility, an invocation of such a method need still neither catch nor declare the exception. - #75: An anonymous or local class that accessed the
final(or, with #24, effectively final) loop variable of a basicfor
statement was an internal compiler error.
Performance
Measured interleaved against 3.1.16 on JDK 25 (janino-benchmarks, with and without JIT), the compile time is
unchanged within the measurement error on all workloads, including the code that Apache Spark generates for
TPC-DS queries; the memory that a compilation allocates changes by less than 1 % (0.1 to 0.9 % more on the
synthetic workloads, 0.8 % less on the Spark code). The generated class files are byte-identical for all workloads.
See the benchmark README.
Tests and documentation
- Changes since 3.1.12 summarizes, for projects that still use 3.1.12, what the releases 3.1.13 to 3.1.17 change;
Compatibility says what stays the same, including the API that Apache Spark uses, which a test now covers. - The compile-time benchmarks gained the code that Apache Spark 4.2.0 generates for twelve TPC-DS queries
(342 class bodies), compiled the way Spark compiles it; see the benchmark README. - 58 more cases of invalid code in the negative tests (now 426; five of them are constructs that Spark's code
generator emits, SPARK-58437), 81 more characterization tests (now 458).
See the change log.
Compatibility notes
- No code that compiled with 3.1.16 is rejected now, and code that compiled before behaves the same.
- The generated class files are unchanged, except for one more
checkcastinstruction where the clone of an array
was used as anObject(#58) and for theExceptionsattribute of a method or constructor whosethrows
clause names an exception type with an all-uppercase name (#65). The compilation of JANINO's own sources and of
the code that Spark generates yields the same class files as with 3.1.16, byte for byte. - Invalid code that JANINO 3.1.12 accepts is still accepted (#33).
- Java 8 or later is required. JANINO is built with JDK 25 and tested on Java 8, 17, 21 and 25.
- The test suites of Apache Calcite (all modules) and of Spark Catalyst (349 suites) pass with this release as
with the Janino versions that the projects declare.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler, commons-compiler-jdk
(each with sources and Javadoc), commons-compiler-tests, and the POMs, including janino-parent.
Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.16
JANINO-3.1.16
Two language features that JANINO parsed, but did not compile, are implemented now: multi-catch clauses and
qualified superclass method invocations. Most fixes concern conditional expressions, annotations, enums and
invalid code that compiled into class files that the JVM rejects; all of the defects exist in 3.1.12 already, except
#51 (a regression of 3.1.15) and #57 (since 3.1.13).
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.16</version>
</dependency>New language features
- #21: Multi-catch clauses,
catch (IOException | SQLException e)
(JLS7 14.20). The type of the parameter is the nearest common superclass of the alternatives, the parameter is
implicitlyfinal, andthrow e;rethrows the alternatives. - #22: Qualified superclass method invocations.
Interface.super.m()invokes a default method of a direct superinterface (target version 8 or later);
Outer.super.m()invokes a superclass method of a lexically enclosing class from an inner class, through a
synthetic accessor method, likejavac.
Fixed
- #51: Since 3.1.15, conditional expressions with a
charoperand and a negativebyteorshortconstant (z ? c : (short) -1) were rejected; they have the typeintnow, like withjavac. The same applies to anintconstant that is not representable in the type of the other operand (z ? b : 500with abyte b), and to abyte,shortorcharoperand with along,floatordoubleconstant. - #55: The constant value of a conditional expression with a
constant condition and operands of different types had the type of the selected operand instead of the type of
the expression:"" + (true ? 1 : 2.0)was"1", andObject o = true ? 1 : 2L;compiled into a class file that the JVM rejects. - #56: Conditional expressions in which one operand has the type
byte,shortorcharand the other operand a different numeric type were rejected, e.g.z ? b : 5andz ? s : c. - #53: A class that implements an interface with a static method was rejected ("must implement method") if the interface was declared in the compiled code.
- #54: Invalid code that compiled into class files that the JVM rejects is rejected with a compile error now: illegal combinations of modifiers, the same interface twice in an
implementsclause, the access to aprotectedmember of another package through an expression of a superclass type (JLS 6.6.2.1, 6.6.2.2), and the use of a local variable that is not definitely assigned. - #57: Since 3.1.13, a local variable that is assigned in the body of a
dostatement, or in the right operand of&&or||, compiled into class files that the JVM rejects ("Inconsistent stackmap frames"); a variable that is assigned in the condition of awhileorforstatement failed with an internal compiler error. - #43: Annotations of annotation types that are declared as member types were invisible at run time, because the member type was compiled as an ordinary interface. The
InnerClassesattribute now records the implicit modifiers of member types. - #61: Annotations on method and constructor parameters were not written to the class files.
- #62: The member types of an interface were not implicitly
public static; anenumdeclared in an interface was a syntax error. - #44: The class bodies of enum constants were ignored, and an enum with an abstract method was rejected.
- #63: An anonymous or local class in a
catchclause could access neither thecatchparameter nor a local variable declared before thetrystatement (internal compiler error). - #66: The qualified superclass field access
Outer.super.fldfrom an inner class was rejected.
Performance
Measured interleaved against 3.1.15 on JDK 25 (janino-benchmarks, with and without JIT), the compile time is
unchanged within the measurement error, and the memory that a compilation allocates grows by 0.2 to 1 %. The class
files of sources with member types, enums or parameter annotations are slightly larger (attributes and flags only,
see the compatibility notes).
Tests and documentation
- Differences between Janino and javac lists all known deviations from
javac; - Janino and javac: the compatibility mode and the compliance mode is a non-binding idea of how they could be handled in the long run.
- 131 more cases of invalid code in the negative tests (now 368), 176 more characterization tests (now 377); the
differential test of control flow statements generates multi-catch clauses as well.
See the change log.
Compatibility notes
-
Code that compiled before behaves differently only where the old behavior was clearly wrong: the class bodies of
enum constants take effect (#44), the annotations of member annotation types are visible at run time (#43),
parameter annotations are written to the class files (#61), and the constant value of a conditional expression
with a constant condition has the type of the expression (#55). -
The generated class files change only for these cases, for the member types of classes and interfaces (#43,
#62) and for thefinalflag of enums (#44); the constant pool entries of classes withforstatements may be
ordered differently (#57). The compilation of JANINO's own sources yields the same instructions as with 3.1.15. -
Some code that JANINO accepted, but
javacrejects, is now rejected as well:- the code of #54, which the JVM rejected anyway, except for the access to a
protectedmember through an
expression of a superclass type, e.g.((Object) this).clone(), which the JVM loaded in some cases; - a constant conditional expression of type
long,floatordoublewhere a narrower type is required, e.g.
byte b = true ? 1 : 2L;(#55); - the forms of a member annotation type that only an ordinary interface permits, e.g. type parameters or an
extendsclause (#43); - a
catchparameter whose type is not aThrowable, e.g.catch (Object e)(#21), which the JVM rejected
anyway.
Other invalid code that JANINO accepts is still accepted (#33).
- the code of #54, which the JVM rejected anyway, except for the access to a
-
Java 8 or later is required. JANINO is built with JDK 25 and tested on Java 8, 17, 21 and 25.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler, commons-compiler-jdk
(each with sources and Javadoc), commons-compiler-tests, and the POMs, including janino-parent.
Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.15
JANINO 3.1.15
The first release of this continuation of JANINO on Maven Central, under the new group ID
io.github.janino-lts:
<dependency>
<groupId>io.github.janino-lts</groupId>
<artifactId>janino</artifactId>
<version>3.1.15</version>
</dependency>The Java packages (org.codehaus.janino, org.codehaus.commons.compiler), the OSGi bundle symbolic names and the
automatic module names are unchanged, so existing code works without changes. If another dependency brings in the
original org.codehaus.janino artifacts, exclude them (see below).
Most fixes of this release concern constant expressions, conversions and annotations; all of the defects exist in
3.1.12 already. They were found by new differential tests (generated expressions, compiled with JANINO and with
javac), negative tests and a review of the constant handling.
Fixed
- #35: The value of a compound assignment used as an expression
(e.g.a[i] += x, orI += 2with anInteger I) was wrong, failed the verification, or crashed the compiler. - #36: The bitwise and shift operators did not unbox their operands
when determining the type of the result (e.g. for overload resolution). - #37: Narrowing conversions to
charand fromchartoshort
generated wrong opcodes, e.g.(int) (char) bwas -1 instead of 65535 forb == -1. - #39: The constant folding of the unary
+and-did not
promotebyte,shortandchartoint, e.g."" + (+'a')was"a"and-Byte.MIN_VALUEwas -128. - #45:
finalfields of typecharwith a constant initializer
were rejected;finalfields of a wrapper or other reference type with a constant initializer (e.g.
static final Integer I = 5;) were rejected or caused aClassFormatError. - #46:
boolean,byte,charandshortconstants of fields
from class files were treated asintconstants, e.g."" + A.F + A.Cwas"197"instead of"truea". - #48: Annotation element values and default values whose type
differs from the element type (e.g.long l() default 0;,@Ann(l = 5)) could not be read through reflection. - #49: The constant folding of string concatenations with
null
(e.g.null + "a") crashed the compiler. - #30: JANINO generated class files that the JVM rejects (e.g. for
overriding a final method, extending a final class, duplicate fields or member types, orint x; x++;); these are
compile errors now. - #32, #34:
Invalid code caused internal compiler errors instead of compile errors, also after a first compile error when the
error handler does not throw. - #19: The
cookFiles(...)methods did not name the files in
compile errors, andcookFiles(String[])always failed with aNullPointerException. - #20: A
NullPointerExceptionwhen a directory could not be
listed (e.g. an extension directory that is a file or does not exist). - #6: New overloads
StringResource(String, String, Charset)and
MapResourceFinder.addResource(String, String, Charset); the "jdk"SimpleCompilerand evaluators no longer
replace characters that the platform default charset cannot represent with?. - The command line compiler reports the correct values of
-g:linesand-g:varswith-verbose.
Performance
#26 removes some small overheads of the compiler. Measured with the
new module janino-benchmarks (#25), interleaved against 3.1.12
on JDK 25: the compilation of JANINO's own sources is about 6 % faster and allocates about 16 % less memory. Code
with many nested try / finally statements compiles somewhat slower than with 3.1.12, because the code that JANINO
generates for them since 3.1.14 is correct, but larger.
New tests
- A differential test that compiles generated expressions with JANINO and with
javacand compares the results
(#28). - Negative tests with 221 cases of invalid code (#29).
See the change log.
Compatibility notes
-
New Maven coordinates:
io.github.janino-lts:janino,io.github.janino-lts:commons-compiler,
io.github.janino-lts:commons-compiler-jdk. Maven does not recognize them as versions of the original
org.codehaus.janinoartifacts. If another dependency brings those in, exclude them, otherwise the same classes are
on the class path twice:<exclusions> <exclusion> <groupId>org.codehaus.janino</groupId> <artifactId>*</artifactId> </exclusion> </exclusions>
-
The generated class files change only where a conversion, a constant value or an annotation was wrong (#37, #39,
#45, #46, #48). -
Some code that JANINO accepted, but
javacrejects, is now rejected as well:byte b = -Byte.MIN_VALUE;(#39);- a statement after
while (A.F) {}with abooleanconstanttruefrom a class file (#46); z ? c : (short) -1with achar c(#45);- the code of #30, which the JVM rejected anyway.
Other invalid code that JANINO accepts is still accepted (#33).
-
Java 8 or later is required. JANINO is built with JDK 25 and tested on Java 8, 17, 21 and 25.
Assets
The artifacts on Maven Central are signed with the PGP key D7FA DB51 D921 93FC A6BA 204D C0D2 FF51 226A 8B8B. This
release additionally contains the same files as the previous releases: janino, commons-compiler,
commons-compiler-jdk (each with sources and JAVADOC), commons-compiler-tests, and the POMs, including
janino-parent. Verify the downloads with:
sha256sum -c SHA256SUMS
janino-3.1.14
JANINO 3.1.14
Experimental fork - proof of concept. This is a release of an experimental fork of JANINO, derived from
janino-compiler/janino, whose author has discontinued its development and archived the original repository.
It is not a commitment to maintain JANINO. If you are interested in continuing the project together, please create an issue.
A bug fix release for the code generation of try statements. Users of 3.1.13 should upgrade: some of the
defects are regressions of 3.1.13, whose default target version 8 (was 6) disabled the JVM's fallback to its old
bytecode verifier, so that code which worked with 3.1.12 failed with a VerifyError. Other defects exist in 3.1.12
already and silently produced wrong results.
Fixed
- #2:
VerifyErrorwhen afinallyblock cannot complete
normally (e.g.try { return x; } finally { return y; }), andVerifyErrors and internal compiler errors when a
return,breakorcontinuestatement leaves atryblock whosefinallyblock contains atry,
synchronized,breakorcontinuestatement. - #3: A
finallyblock was executed twice when acatch
clause handled an exception, and when the copy of afinallyblock that is executed before a jump statement threw
an exception. - #4: Try-with-resources statements now close the resources when
the block completes byreturn,breakorcontinue, record the exceptions fromclose()as suppressed
exceptions, and close the resources before thecatchclauses and thefinallyblock are executed
(JLS 14.20.3). - #5: A
finallyblock was executed twice (and the monitor
released twice) when a jump statement left asynchronizedstatement inside atrystatement and thefinally
block threw an exception. - #7: Internal compiler errors and
VerifyErrors after atry
statement whosetryblock cannot complete normally, e.g. the common pattern
try { return Integer.parseInt(s); } catch (A e) { ... } catch (B e) { ... }followed by more code.
Some of these fixes change the behavior of code that compiled before (e.g. a finally block that is no longer
executed twice, or a resource that is now closed); in every case, the new behavior is the one that the Java language
requires.
New tests
- Characterization tests for about 200 language constructs: each test records the correct result (verified with
the JDK-based compiler) and JANINO's current behavior, also for the constructs that JANINO does not support yet, so
that every change of JANINO's behavior is deliberate. - A differential test that generates 2,000 methods with nested control flow (
try/catch/finally,
try-with-resources, loops,switch,synchronized, labeled blocks,break,continue,return,throw),
compiles them with JANINO and withjavac, and compares the results. With 3.1.13, about a quarter of such
methods failed or produced wrong results; with 3.1.14, all of them behave like thejavac-compiled code.
See the change log.
Compatibility notes
- Java 8 or later is required. JANINO is built with JDK 25 and tested on Java 8, 17, 21 and 25.
- The artifacts use the same Maven coordinates as the original (
org.codehaus.janino:*), but they are not
published on Maven Central. Do not mix them with the official versions.
Assets
The same set of artifacts as the original JANINO releases on Maven Central: janino, commons-compiler,
commons-compiler-jdk (each with sources and JAVADOC), commons-compiler-tests, and the POMs, including
janino-parent. Verify the downloads with:
sha256sum -c SHA256SUMS
To use the artifacts with Maven, install them into your local repository (the parent POM first):
mvn install:install-file -Dfile=janino-parent-3.1.14.pom -DpomFile=janino-parent-3.1.14.pom
mvn install:install-file -Dfile=commons-compiler-3.1.14.jar -DpomFile=commons-compiler-3.1.14.pom
mvn install:install-file -Dfile=janino-3.1.14.jar -DpomFile=janino-3.1.14.pom
(Optionally add -Dsources=...-sources.jar -Djavadoc=...-javadoc.jar.) Then depend on
org.codehaus.janino:janino:3.1.14 as usual; commons-compiler comes in as a transitive dependency.
janino-3.1.13
JANINO 3.1.13
This is a release of an experimental fork of JANINO, derived from janino-compiler/janino, whose author
has discontinued its development and archived the original repository.
It is not a commitment to maintain JANINO. If you are interested in continuing the project together,
please create an issue.
The experiment: JANINO's sandbox relies on the Java security manager, which is permanently disabled since Java 24.
This fork replaces it with an (optional, opt-in) mechanism that works on all current JREs: a sandbox policy (an allowlist of
the APIs that compiled code may use, enforced by a bytecode verifier before the classes are loaded), plus resource limits
(CPU time and memory, also optional / opt-in) for executing the compiled code. The default behavior of Janino is unchanged,
but it requires Java 8 or later now.
What's new since 3.1.13-SNAPSHOT-1
- Resource limits: The new
SandboxExecutorexecutes sandboxed code underSandboxLimits(timeout, number of
"ticks", allocated memory). JANINO inserts checks into the code that it compiles with a sandbox policy; once a
limit is exceeded, the code is stopped, even if it catches the error. Code compiled by the JDK-based
implementation is only subject to the timeout. SandboxPolicy.Builder.requireExecutor(): Sandboxed code fails if it is executed outside of a
SandboxExecutor(e.g. a static initializer, or thetoString()method of a returned object), so that it cannot
run without limits by accident.- The sandbox verifier rejects
finalize()declarations, and reports violations with their source file and line. - New sandbox policy presets:
FUNCTIONAL,STREAMS,MATH,REGEX,JAVA_TIME,TEXTandUTILITIES. - The security-manager-based
Sandboxis deprecated. It keeps working where the security manager is available
(Java 8 - 17, and 18 - 23 with-Djava.security.manager=allow). - Mitigated issue #226 of the original project (escape from
theSandboxthroughAccessController.doPrivileged()): the newICookable.setProtectionDomain()defines the
generated classes with a restricted protection domain. The default behavior is unchanged. - JANINO's default target version is now 8 (was 6), and an invalid
StackMapTablefordostatements ending with
continuewas fixed.
See the change log,
Restricting Untrusted Code with a Sandbox Policy and
the project homepage (including the JAVADOC).
Compatibility notes
- Java 8 or later is required. JANINO is built with JDK 25 and tested on Java 8, 17, 21 and 25.
- The artifacts use the same Maven coordinates as the original (
org.codehaus.janino:*), but they are not
published on Maven Central. Do not mix them with the official versions.
Assets
The same set of artifacts as the original JANINO releases on Maven Central: janino, commons-compiler,
commons-compiler-jdk (each with sources and JAVADOC), commons-compiler-tests, and the POMs, including
janino-parent. Verify the downloads with:
sha256sum -c SHA256SUMS
To use the artifacts with Maven, install them into your local repository (the parent POM first):
mvn install:install-file -Dfile=janino-parent-3.1.13.pom -DpomFile=janino-parent-3.1.13.pom
mvn install:install-file -Dfile=commons-compiler-3.1.13.jar -DpomFile=commons-compiler-3.1.13.pom
mvn install:install-file -Dfile=janino-3.1.13.jar -DpomFile=janino-3.1.13.pom
(Optionally add -Dsources=...-sources.jar -Djavadoc=...-javadoc.jar.) Then depend on
org.codehaus.janino:janino:3.1.13 as usual; commons-compiler comes in as a transitive dependency.
janino-3.1.13-S1
JANINO 3.1.13-SNAPSHOT-1 (pre-release)
Experimental fork - proof of concept. This is a pre-release of an experimental fork of JANINO, derived from
janino-compiler/janino, whose author has discontinued its development
and archived the original repository. It is not a commitment to maintain JANINO. If you are interested in
continuing the project together, please create an issue.
This pre-release explores how JANINO can be kept working on current JREs.
What's new
- Java 8 or later is now required (formerly Java 7). JANINO is built with JDK 25 and tested on Java 8, 17, 21
and 25. - Sandbox policies: Restrict the APIs that compiled code may use, on all JREs from Java 8 on, without the Java
security manager. Generated classes are verified against an allowlist before they are loaded; code that uses
anything else is rejected at compile time. See
Restricting Untrusted Code with a Sandbox Policy.
New API:ICookable.setSandboxPolicy(),AbstractJavaSourceClassLoader.setSandboxPolicy()and the package
org.codehaus.commons.compiler.sandbox. - The security-manager-based
Sandboxkeeps working where the security manager is available (Java 8 - 17, and
18 - 23 with-Djava.security.manager=allow). On other JREs it now fails with a descriptive
UnsupportedOperationExceptioninstead of anExceptionInInitializerError. New methodSandbox.isSupported(). - New method
AbstractJavaSourceClassLoader.setTargetVersion(int). - Calls to
AccessController.doPrivileged()are now made through a helper, so that JANINO keeps working on future
JREs that no longer provide that API. - Pull request #214: Correctly parse and unparse annotated wildcards.
- JAVADOC fixes.
See the change log and the
project homepage (including the
JAVADOC).
Compatibility notes
- The minimum Java version is now 8.
- The artifacts use the same Maven coordinates as the original (
org.codehaus.janino:*), but they are not
published on Maven Central. Do not mix them with the official versions.
Assets
The same set of artifacts as the original JANINO releases on Maven Central: janino, commons-compiler,
commons-compiler-jdk (each with sources and JAVADOC), commons-compiler-tests, and the POMs, including
janino-parent. Verify the downloads with:
sha256sum -c SHA256SUMS
To use the artifacts with Maven, install them into your local repository (the parent POM first):
mvn install:install-file -Dfile=janino-parent-3.1.13-SNAPSHOT-1.pom -DpomFile=janino-parent-3.1.13-SNAPSHOT-1.pom
mvn install:install-file -Dfile=commons-compiler-3.1.13-SNAPSHOT-1.jar -DpomFile=commons-compiler-3.1.13-SNAPSHOT-1.pom
mvn install:install-file -Dfile=janino-3.1.13-SNAPSHOT-1.jar -DpomFile=janino-3.1.13-SNAPSHOT-1.pom
(Optionally add -Dsources=...-sources.jar -Djavadoc=...-javadoc.jar.) Then depend on
org.codehaus.janino:janino:3.1.13-SNAPSHOT-1 as usual; commons-compiler comes in as a transitive dependency.