GroupDocs.Assembly for Java 26.10 Release Notes
Full list of changes in this release
| ID | Summary | Category |
|---|---|---|
| ASSEMBLYJAVA | Plain Java objects work as data sources on JDK 16 and later without JVM flags. The generated member binders were defined through a reflective ClassLoader.defineClass, which is refused once java.base/java.lang is closed, so every method of a POJO was reported as “Can not resolve method”. They are defined through MethodHandles.Lookup now | Fix |
| ASSEMBLYJAVA | Data models typed by an interface can be used. The generated binders called interface methods with invokevirtual and failed with IncompatibleClassChangeError: Found interface ..., but class was expected | Fix |
| ASSEMBLYJAVA | Indexer syntax obj["key"] works on Java objects. It resolves to a call of get_Item or get with the same arguments, which covers java.util.Map and java.util.List | Feature |
| ASSEMBLYJAVA-257 | A JSON object such as root or root.person can be passed to a known-type method that takes a single DataRow; port of the .NET fix of ASSEMBLYNET-59 | Fix |
| ASSEMBLYJAVA | A java.lang.Boolean value is accepted where a Boolean expression is required: <<if>>, <<check>> and the removal flag of a chart series refused it with “A conditional expression should return a Boolean value” | Fix |
| ASSEMBLYJAVA | A presentation chart whose title is deleted no longer brings the assembly down with an internal NullPointerException | Fix |
| ASSEMBLYJAVA | No UnsatisfiedLinkError stack traces logged at SEVERE on Windows on the first render that needs font data. The native library of Aspose.Words cannot bind inside the repackaged jar and is no longer bundled | Fix |
| ASSEMBLYJAVA | BarcodeSettings.setResolution, setXResolution and setYResolution are public, as in .NET | Fix |
| ASSEMBLYJAVA | build.cake: the security report task prints the tool, its configuration, the project key and the folders it reads and copies the report from, and names the configuration file when no report is produced | Update |
Plain Java objects on JDK 17 and later
On JDK 17 and later every template that took its data from a plain Java object failed, while the same code worked on JDK 8 and 11:
Can not resolve method 'getCustomer' on type 'class Order'.
The engine generates a member binder class per data type at run time. Up to 26.9 it defined that class by calling the protected ClassLoader.defineClass through reflection. JDK 16 closed java.base/java.lang to reflection, so the call was refused, no binder was built and the engine reported the method as missing. The class is now defined through MethodHandles.privateLookupIn(...).defineClass(...), a public API since Java 9 that needs no access to JDK internals. On Java 8 the previous path is kept. If a binder still cannot be generated, the engine falls back to plain reflection instead of failing the lookup.
The two workarounds for earlier versions, DocumentAssembler.setUseReflectionOptimization(false) and --add-opens java.base/java.lang=ALL-UNNAMED, are no longer needed and do no harm if they stay in place. On JDK 11 the “illegal reflective access” warning of the previous path is gone as well.
Verified with the example suite on JDK 8, 17 and 21. Without flags 26.10 gives the same results as 26.9 with --add-opens, where 26.9 without flags failed 92 of 99 scenarios.
Interface-typed data models
A data object whose members are typed by an interface, for example a Collection<IItem>, could not be iterated at all:
IncompatibleClassChangeError: Found interface IItem, but class was expected
The generated binder called every instance method with invokevirtual, which the JVM refuses when the owner of the method is an interface. Interface methods are called with invokeinterface now. Iteration, where(...), count() and methods declared by a superinterface work on such models.
Indexer syntax on Java objects
Templates written for .NET often use indexer syntax, such as <<[root["Name"]]>>. Java has no indexers, so this syntax never resolved on a Java object and failed with “Can not resolve an indexer”. It is now resolved the way the C# compiler lowers an indexer, as a call of an instance method with the same arguments: get_Item first, then get. That covers java.util.Map (root["Name"], null for a missing key), java.util.List (root.getList()[1]) and any class that declares get(String) or get(int). Arrays resolve their elements as before.
JSON objects passed to a DataRow parameter (ASSEMBLYJAVA-257)
A method of a known type that takes a single DataRow could not be called with a JSON object reached by name, such as root of {"root": {...}} or root.person:
<<[Funcs.rowName(root.person)]>>
Can not resolve method 'rowName' on type 'class Funcs'.
Such an object is represented by the rows related to its parent, not by a DataRow, so only an Iterable<DataRow> parameter matched it. This is the fix of ASSEMBLYNET-59 made in GroupDocs.Assembly for .NET 26.7, ported as is: when no method matches the arguments as they are, the resolution is retried with every such argument unwrapped to its single related row, which is how member access such as root.person.firstName already treats it. An overload that matches without unwrapping, one taking Iterable<DataRow> or Object, still wins, so templates that work today keep calling the same method. A reference that yields several rows, such as a JSON array, fails with “A single child data row is expected, but multiple child data rows are found”.
The workarounds suggested for ASSEMBLYJAVA-257 before, a parameter of type Iterable<DataRow> or Object that takes the row out itself, keep working unchanged.
java.lang.Boolean in conditions
A Boolean passed as a data source printed fine with <<[flag]>>, but <<if [flag]>> and the documented <<check [conditional_expression]>> rejected it:
Tag 'if' is not well-formed. A conditional expression should return a Boolean value.
A getter declared as returning Boolean was rejected the same way. The check compared the type of the expression with the primitive boolean only. It accepts the wrapper as well now, in <<if>>, in <<check>> and in the removal flag of a chart series. Expressions of other types are still rejected with the same message.
Presentation charts whose title is deleted
A presentation chart with its title deleted, such as Chart with Filtering, Grouping, and Ordering.pptx of the example suite, brought the assembly down with an internal error:
java.lang.IllegalStateException: Cannot invoke "...a()" because the return value of "...l()" is null
While a chart series is assembled, its name is kept in the text frame of the chart title, and a chart without a title has no such frame. The frame is now created when it is missing. The chart title is not restored, and the saved chart still has no title. Problems in the tags of such a chart are now reported with the regular template error messages.
UnsatisfiedLinkError during font substitution
Since 26.7, the first render that needed font data on Windows logged two UnsatisfiedLinkError stack traces at SEVERE level and then continued normally. The native library that ships with Aspose.Words exports its JNI entry points under the original package and method names. Inside this jar that class is repackaged and obfuscated, so the library could never bind. It is no longer bundled: the managed code path, which was already being used after the error, is taken from the start. The assembled documents are the same. The loader still prints a one-line notice to System.err, up to three times per JVM and without a stack trace: Aspose.Words native libs cannot be loaded. ... WindowsNativeCall_x64.dll cannot be found.
Barcode resolution
BarcodeSettings.setResolution, setXResolution and setYResolution lost their public modifier in the port, while the neighbouring properties kept theirs. They are public again, so the resolution of generated barcode images can be set from Java as in .NET:
DocumentAssembler assembler = new DocumentAssembler();
assembler.getBarcodeSettings().setResolution(300);