GroupDocs.Assembly for Java 26.10.1 Release Notes

26.10.1 is a maintenance release of 26.10. Most importantly, the library no longer breaks the XML processing of the application it is part of. Since 26.7 it had registered its embedded XML parser as the StAX provider of the whole JVM, under a class name it does not contain. The release also fixes the remaining defects found with the example suite, and data sources written for GroupDocs.Assembly for .NET now work with idiomatic Java data classes. The bundled Aspose components, the public API and the Java 8 baseline are the same as in 26.10.

Full list of changes in this release

IDSummaryCategory
ASSEMBLYJAVAApplications that use StAX work again with GroupDocs.Assembly on the class path. Since 26.7 the jar had registered the embedded Woodstox parser as the StAX provider of the JVM under a class name it does not contain, so every XMLInputFactory.newInstance() failed with ServiceConfigurationError: ... Provider com.ctc.wstx.stax.WstxInputFactory not foundFix
ASSEMBLYJAVANo “Aspose.Words native libs cannot be loaded” lines on System.err any moreFix
ASSEMBLYJAVAA DataTable renamed with setTableName() is found under its new name, by DataTableCollection.get() and by templates alikeFix
ASSEMBLYJAVAThe items of a List, Set or Map passed directly as a data source are typed by their class instead of Object, so <<foreach [in orders]>><<[Price]>> and orders.sum(c => c.Price) work for a List<Order>Fix
ASSEMBLYJAVAMembers typed by a type variable of a generic class get the type argument of the instance: orders.get(1).Price of a List<Order>, map.get("a").Price of a Map<String, Order>, Optional<Order>.get(), box.getValue() of a Box<Order>, the entries of map.entrySet()Fix
ASSEMBLYJAVAProperty syntax resolves JavaBean getters: x.Name reads getName(), or isName() for a boolean, when there is no public field of that nameFeature
ASSEMBLYJAVAThe keys of a java.util.Map can be read with member syntax: map.Name reads map.get("Name"), including contextual access such as <<[Name]>>Feature
ASSEMBLYJAVArow["column"] and row[0] work on the data rows of JSON, XML and database sources, as do ds["Table"] on a DataSet and x["relation"] on a related rowFeature
ASSEMBLYJAVAtoString(), equals(), hashCode() and getClass() can be called on a value whose type is an interfaceFix
ASSEMBLYJAVAA null java.lang.Boolean counts as false in <<if>>, <<check>>, chart series removal flags and the && and || operators, instead of failing with a NullPointerExceptionFix
ASSEMBLYJAVABarcodeSettings.setResolution() makes barcodes sharper instead of larger: the image carries the requested resolution, and its size in the document stays the size the template gives itFix
ASSEMBLYJAVA-316Maven metadata standardized: the artifact is named GroupDocs.Assembly for Java, has a short product-specific description, and declares its organization, license and public repository (scm)Update

StAX provider of the application

GroupDocs.Assembly embeds the Woodstox XML parser under an internal package name, so it cannot clash with a Woodstox of the application. Since 26.7, however, the jar also contained the service registration files of Woodstox: META-INF/services/javax.xml.stream.XMLInputFactory, XMLOutputFactory, XMLEventFactory and three org.codehaus.stax2.validation files. They still named the original classes, such as com.ctc.wstx.stax.WstxInputFactory, which the jar does not contain under those names. The JDK finds StAX implementations through exactly these files. So every XMLInputFactory.newInstance(), XMLOutputFactory.newInstance() and XMLEventFactory.newInstance() of an application with GroupDocs.Assembly on its class path failed, whether the application called it itself or through JAXB, Spring, Jackson XML and the like, and whether or not it used GroupDocs.Assembly at all:

java.util.ServiceConfigurationError: javax.xml.stream.XMLInputFactory:
    Provider com.ctc.wstx.stax.WstxInputFactory not found

GroupDocs.Assembly creates its Woodstox factories directly and never looks them up, so the files are no longer shipped. The application gets its own StAX implementation again: the JDK one, or its own Woodstox if it has one. To keep using 26.7 to 26.10, either add com.fasterxml.woodstox:woodstox-core to the application, or set the system properties javax.xml.stream.XMLInputFactory, javax.xml.stream.XMLOutputFactory and javax.xml.stream.XMLEventFactory to the JDK implementations com.sun.xml.internal.stream.XMLInputFactoryImpl, com.sun.xml.internal.stream.XMLOutputFactoryImpl and com.sun.xml.internal.stream.events.XMLEventFactoryImpl.

Native library of Aspose.Words

26.10 stopped bundling the Windows native library of Aspose.Words, because it cannot bind inside the repackaged jar. Aspose.Words still looked for it on the first font initialisation and printed Aspose.Words native libs cannot be loaded ... cannot be found to System.err three times per JVM. GroupDocs.Assembly now tells Aspose.Words to skip the library (NativeLibSettings.skipWinNativeLib()) before the first document is opened, so nothing is printed. Font handling takes the managed path, as it did in 26.10.

Data tables renamed with setTableName()

DataTableCollection indexes its tables by name, but DataTable.setTableName() only changed the name, not the index. After a rename, getTables().get(newName) returned null, and templates found the table only under its old name. This made the .NET pattern of renaming the table that DataSet.readXml() creates impossible to port:

DataSet ds = new DataSet();
ds.readXml("Products.xml");
ds.getTables().get("Products").setTableName("Product");   // <<foreach [in product]>> failed

The collection now re-indexes a renamed table, keeping its position. As in .NET, the old name no longer resolves.

Element types of collections and maps

Java erases type arguments at run time, so a List<Order> passed directly as a data source used to have its items typed as Object:

Can not get the value of member 'Price' on type 'class java.lang.Object'.

The same data passed as an Order[], or returned by a List<Order> getter, worked. A collection passed as a data source is now typed by the nearest common class of its items, for ArrayList, Arrays.asList, LinkedHashSet, the unmodifiable wrappers and the like. A map is typed the same way by its keys and its values. Items of mixed classes that share only Object stay Object, and null items are skipped.

Type variables in member types

A member declared through a type variable of its class was typed by its erasure, Object. This covers E get(int) of List, V get(Object) of Map, T get() of Optional, and the getter of a generic class of your own. Such members are now typed by the type argument the instance is known to have, taken from the generic signature of the getter that returned it, from the data source it came from, or from a subclass such as class OrderBox extends Box<Order>:

<<[orders.get(1).Price]>>
<<[x.getMap()["b"].Price]>>
<<foreach [e in x.getMap().entrySet()]>><<[e.getKey()]>>=<<[e.getValue().Price]>><</foreach>>

A raw List still gives Object, since there is nothing to resolve it from.

JavaBean getters and map keys with property syntax

Templates written for GroupDocs.Assembly for .NET address members as properties, such as customer.CustomerName. In Java, that syntax used to resolve only against a public field. Now, when there is no field of that name:

  • on a java.util.Map, map.Name reads map.get("Name"), as map["Name"] does. A missing key gives an empty value, and methods such as map.size() are calls as before.
  • on any other object, x.Name reads a public no-argument getName(), or isName() for a boolean or Boolean result.

This applies to explicit and contextual member access, lambdas, conditions and arithmetic alike. A public field of the name still takes precedence. The data rows of JSON, XML and database sources are not affected: a missing column is still a missing member, rather than being answered by a getter of DataRow.

row["column"] on data rows

The data rows of JSON, XML and database sources resolved their columns as members (row.firstName), but did not support an indexer, so row["firstName"] failed with Can not resolve an indexer. An index with a literal argument is now resolved as member access: row["firstName"] reads the column, row[0] reads the first column, ds["Products"] gives a table of a DataSet, and x["relation"] follows a relation. The result has the type of the column, so row["age"] + 1 is arithmetic rather than concatenation. A column that does not exist still fails, or is a missing member with ALLOW_MISSING_MEMBERS.

Methods of Object on interface types

Class.getMethods() of an interface does not list the methods of Object, so a value whose static type was an interface could not even be converted with toString():

Can not resolve method 'toString' on type 'interface IItem'.

For an interface, the public methods of Object are now available as well, unless the interface declares them itself.

null Boolean values in conditions

Since 26.10, conditions accept java.lang.Boolean, and a null value then made the assembly fail with a NullPointerException. A null now counts as false:

  • <<if>> takes its else branch;
  • <<check>> leaves the box unchecked;
  • a chart series removal flag keeps the series;
  • null && x is false without evaluating x, and null || x is x.

Comparisons were already safe: flag == true is false for null. !flag stays null, as the lifted operator of C# makes it, so for a null flag both <<if [flag]>> and <<if [!flag]>> take the else branch.

Barcode resolution

The resolution setters added in 26.10 rendered a barcode with the pixels of the requested resolution, but tagged the PNG with the standard 96 dpi, and the document sizes a picture from that tag. A higher resolution therefore made the barcode physically larger instead of sharper. At 300 dpi it was 10.85 inches wide instead of 3.47. In Word it was clamped at 22 inches from about 610 dpi, and in a workbook it grew to 52 inches at 1600 dpi. The image now carries the requested resolution in its pHYs chunk, so the barcode keeps the size of the template at every setting, for example 1041 × 475 pixels in a 3.47 × 1.58 inch shape at 300 dpi.

Not changed in this release

  • Documents assembled without a license carry the evaluation watermark of Aspose.Words rather than one of GroupDocs.Assembly. The Java editions of the Aspose components offer no way to replace it.
  • A Map whose values are of unrelated classes, such as strings next to nested maps, types its values as Object, so their members cannot be resolved statically.
  • row[key] with a key that is not a literal is not supported on data rows.