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
| ID | Summary | Category |
|---|---|---|
| ASSEMBLYJAVA | Applications 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 found | Fix |
| ASSEMBLYJAVA | No “Aspose.Words native libs cannot be loaded” lines on System.err any more | Fix |
| ASSEMBLYJAVA | A DataTable renamed with setTableName() is found under its new name, by DataTableCollection.get() and by templates alike | Fix |
| ASSEMBLYJAVA | The 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 |
| ASSEMBLYJAVA | Members 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 |
| ASSEMBLYJAVA | Property syntax resolves JavaBean getters: x.Name reads getName(), or isName() for a boolean, when there is no public field of that name | Feature |
| ASSEMBLYJAVA | The 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 |
| ASSEMBLYJAVA | row["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 row | Feature |
| ASSEMBLYJAVA | toString(), equals(), hashCode() and getClass() can be called on a value whose type is an interface | Fix |
| ASSEMBLYJAVA | A null java.lang.Boolean counts as false in <<if>>, <<check>>, chart series removal flags and the && and || operators, instead of failing with a NullPointerException | Fix |
| ASSEMBLYJAVA | BarcodeSettings.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 it | Fix |
| ASSEMBLYJAVA-316 | Maven 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.Namereadsmap.get("Name"), asmap["Name"]does. A missing key gives an empty value, and methods such asmap.size()are calls as before. - on any other object,
x.Namereads a public no-argumentgetName(), orisName()for abooleanorBooleanresult.
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 && xis false without evaluatingx, andnull || xisx.
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
Mapwhose values are of unrelated classes, such as strings next to nested maps, types its values asObject, so their members cannot be resolved statically. row[key]with a key that is not a literal is not supported on data rows.