Skip to content

Releases: janino-lts/janino

janino-3.1.20

Choose a tag to compare

@stefan-zobel stefan-zobel released this 14 Oct 10:14
29ff218

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 a NoSuchMethodError. Now such a local class gets a number, like
    with javac (P$2L, or P$1L next to a member class L); the names of all other local classes are unchanged.
  • #136: super.m() for a private method of the superclass
    P, in a subclass of P declared in P, failed at run time with a NoSuchMethodError.
  • #150: super.s() for a static method of the superclass
    failed at run time with an IncompatibleClassChangeError; 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 (VerifyError on Java 25,
    IncompatibleClassChangeError on 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 parameter Object..., e.g. f(1, new int[] { 1, 2 }) with f(Integer i, Object... a).
  • #134: Some invocations of overloaded methods or constructors
    with a null argument (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) with g(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 type Boolean.
  • #154: A public or protected member of a class that is not
    accessible, inherited through an accessible subclass, e.g. p.B.m() with public class B extends A and a
    package-private class A.

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 nested try / finally statements 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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 10 Oct 14:02
6b755fc

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 extends Outer (also in a class nested in it, and in an anonymous
    or local subclass of Outer) 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 Q with
    class Q extends P in P, compiled into a class that the JVM rejected (VerifyError).
  • #87, the part that changes behavior: a protected member type could not be used from a subclass of the enclosing
    type in another package (IllegalAccessError); its class file now has the flag ACC_PUBLIC, like with javac.
  • #113: A conditional expression with a constant condition in the initializer of a static final field,
    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, 07e1 or 07f, were rejected. They compile now, except
    with an underscore directly before the first digit 8 or 9, e.g. 0_9.5. Invalid octal literals such as 09 are 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 nested try / finally statements 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 protected member 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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 08 Oct 14:31
959a60a

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() and ScriptEvaluator.guessParameterNames() did
    not find the names in the initializers of local variables and fields and in array initializers,
    e.g. x in int y = x; return y; and a, b in new 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; DownstreamApiTest uses 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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 07 Oct 23:14
a857e0f

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 catch parameter or the variable of an
    enhanced for statement that is not declared final, 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 that javac accepts and JANINO still rejects.

Fixed

  • #58: clone() of an array had the type Object instead of the array type (JLS 10.7): int[] b = a.clone(); was rejected,
    and a.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 protected member that an enclosing class inherits from a class in another package, accessed from an inner class,
    compiled into a class that throws an IllegalAccessError or fails to verify. Like javac, JANINO now generates a synthetic
    accessor method in the enclosing class.
  • #65, in part: A type in the throws clause of a method whose simple name consists of uppercase letters only (throws IOEXC)
    was taken for a type parameter and ignored, so the catch of such an exception was "unreachable", and the Exceptions
    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 basic for
    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 checkcast instruction where the clone of an array
    was used as an Object (#58) and for the Exceptions attribute of a method or constructor whose throws
    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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 06 Oct 22:02
6bc03dd

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
    implicitly final, and throw 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, like javac.

Fixed

  • #51: Since 3.1.15, conditional expressions with a char operand and a negative byte or short constant (z ? c : (short) -1) were rejected; they have the type int now, like with javac. The same applies to an int constant that is not representable in the type of the other operand (z ? b : 500 with a byte b), and to a byte, short or char operand with a long, float or double constant.
  • #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", and Object o = true ? 1 : 2L; compiled into a class file that the JVM rejects.
  • #56: Conditional expressions in which one operand has the type byte, short or char and the other operand a different numeric type were rejected, e.g. z ? b : 5 and z ? 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 implements clause, the access to a protected member 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 do statement, 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 a while or for statement 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 InnerClasses attribute 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; an enum declared 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 catch clause could access neither the catch parameter nor a local variable declared before the try statement (internal compiler error).
  • #66: The qualified superclass field access Outer.super.fld from 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

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 the final flag of enums (#44); the constant pool entries of classes with for statements 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 javac rejects, is now rejected as well:

    • the code of #54, which the JVM rejected anyway, except for the access to a protected member 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, float or double where 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
      extends clause (#43);
    • a catch parameter whose type is not a Throwable, e.g. catch (Object e) (#21), 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.15

Choose a tag to compare

@stefan-zobel stefan-zobel released this 06 Oct 01:20
1229e3c

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, or I += 2 with an Integer 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 char and from char to short
    generated wrong opcodes, e.g. (int) (char) b was -1 instead of 65535 for b == -1.
  • #39: The constant folding of the unary + and - did not
    promote byte, short and char to int, e.g. "" + (+'a') was "a" and -Byte.MIN_VALUE was -128.
  • #45: final fields of type char with a constant initializer
    were rejected; final fields of a wrapper or other reference type with a constant initializer (e.g.
    static final Integer I = 5;) were rejected or caused a ClassFormatError.
  • #46: boolean, byte, char and short constants of fields
    from class files were treated as int constants, e.g. "" + A.F + A.C was "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, or int 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, and cookFiles(String[]) always failed with a NullPointerException.
  • #20: A NullPointerException when 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" SimpleCompiler and evaluators no longer
    replace characters that the platform default charset cannot represent with ?.
  • The command line compiler reports the correct values of -g:lines and -g:vars with -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 javac and 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.janino artifacts. 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 javac rejects, is now rejected as well:

    • byte b = -Byte.MIN_VALUE; (#39);
    • a statement after while (A.F) {} with a boolean constant true from a class file (#46);
    • z ? c : (short) -1 with a char 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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 04 Oct 15:33
37510fb

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: VerifyError when a finally block cannot complete
    normally (e.g. try { return x; } finally { return y; }), and VerifyErrors and internal compiler errors when a
    return, break or continue statement leaves a try block whose finally block contains a try,
    synchronized, break or continue statement.
  • #3: A finally block was executed twice when a catch
    clause handled an exception, and when the copy of a finally block that is executed before a jump statement threw
    an exception.
  • #4: Try-with-resources statements now close the resources when
    the block completes by return, break or continue, record the exceptions from close() as suppressed
    exceptions, and close the resources before the catch clauses and the finally block are executed
    (JLS 14.20.3).
  • #5: A finally block was executed twice (and the monitor
    released twice) when a jump statement left a synchronized statement inside a try statement and the finally
    block threw an exception.
  • #7: Internal compiler errors and VerifyErrors after a try
    statement whose try block 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 with javac, 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 the javac-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

Choose a tag to compare

@stefan-zobel stefan-zobel released this 04 Oct 11:01
7a29811

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 SandboxExecutor executes sandboxed code under SandboxLimits (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 the toString() 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, TEXT and UTILITIES.
  • The security-manager-based Sandbox is 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
    the Sandbox through AccessController.doPrivileged()): the new ICookable.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 StackMapTable for do statements ending with
    continue was 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-S1 Pre-release
Pre-release

Choose a tag to compare

@stefan-zobel stefan-zobel released this 03 Oct 20:55

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 Sandbox keeps 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
    UnsupportedOperationException instead of an ExceptionInInitializerError. New method Sandbox.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.