Project

Profile

Help

XdmValue.toString giving UnsupportedOperationException, perhaps through default Receiver implementation: problem only occurs in CheerpJ environment

Added by Martin Honnen 7 months ago

I am experimenting with running Saxon Java HE (using 11.6 at the moment) in the browser, using a tool CheerpJ (in a preview version 3) that compiles Java (class/jars) to web assembly and runs that. so far with mostly surprising/promising results.

For some reasons (that might be due to deficits/shortcomings of CheerpJ, I am investigating partly in their discord server, partly here) trying to use toString() on an XdmValue gives an UnsupportedOperationException, a stack trace is like

Exception in thread "Thread-0" java.lang.UnsupportedOperationException at java.lang.Exception.<init>(Unknown Source) at java.lang.RuntimeException.<init>(Unknown Source) at java.lang.UnsupportedOperationException.<init>(Unknown Source) at net.sf.saxon.event.Receiver.append(Unknown Source) at net.sf.saxon.event.Receiver.append(Unknown Source) at net.sf.saxon.event.SequenceCopier$$Lambda$16.accept(Unknown Source) at net.sf.saxon.om.SequenceTool.supply(Unknown Source) at net.sf.saxon.event.SequenceCopier.copySequence(Unknown Source) at net.sf.saxon.s9api.XdmValue.toString(Unknown Source) at org.example.Main.main(Unknown Source)

Saxon's Receiver in the default implementation in that interface https://saxonica.plan.io/projects/saxonmirrorhe/repository/he/revisions/he_mirror_saxon_11_6/entry/src/main/java/net/sf/saxon/event/Receiver.java#L176 does indeed throw new UnsupportedOperationException(); but when running Saxon code with a "normal" Java 8 JRE/JDK I never get such an exception, instead it seems some Receiver implementation is used that knows to serialize any XdmItems in the XdmValue sequence to a String, I think that is done in https://saxonica.plan.io/projects/saxonmirrorhe/repository/he/revisions/he_mirror_saxon_11_6/entry/src/main/java/net/sf/saxon/s9api/XdmValue.java#L300 with e.g.

    public String toString() {
        try {
            Configuration config = null;
            SequenceIterator iter = value.iterate();
            Item item;
            while ((item = iter.next()) != null) {
                if (item instanceof NodeInfo) {
                    config = ((NodeInfo)item).getConfiguration();
                    break;
                }
            }
            if (config == null) {
                config = Configuration.newConfiguration();
            }
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            SerializationProperties properties = new SerializationProperties();
            properties.setProperty(OutputKeys.METHOD, "adaptive");
            properties.setProperty(OutputKeys.INDENT, "true");
            properties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "true");
            Receiver r = config.getSerializerFactory().getReceiver(result, properties);
            SequenceCopier.copySequence(value.iterate(), r);
            return writer.toString();
        } catch (XPathException e) {
            return super.toString();
        }

    }

Does anyone familiar with the Saxon code have an idea how/whether perhaps Receiver r = config.getSerializerFactory().getReceiver(result, properties); could go wrong to use the default append from the interface?

I understand this is not an issue in the Saxon code, only when run in that experimental Java to web assembly environment, but as I am bit lost in Saxon's source once it goes below the net.sf.saxon.s9api level I am hoping someone here can give me some pointers or speculation as to what might fail.


Replies (3)

Please register to reply

RE: XdmValue.toString giving UnsupportedOperationException, perhaps through default Receiver implementation: problem only occurs in CheerpJ environment - Added by Martin Honnen 7 months ago

The CheerpJ guys have identified that "The actual issue is some subtle interaction with complex class hierarchies and defaulted interface methods." so it seems it will be resolved without me needing further information from the Saxon community; you can ignore this question.

RE: XdmValue.toString giving UnsupportedOperationException, perhaps through default Receiver implementation: problem only occurs in CheerpJ environment - Added by Michael Kay 7 months ago

It's certainly conceivable that this is failing, but we would need to see a repro with the standard SaxonJ product. Perhaps the method should catch all exceptions, and not just XPathException.

Having the two defaulted append() methods in the Receiver interface is certainly a bit fragile. If I keep the method declaration in the interface, but remove the implementation, I get quite a few compile errors from classes that fail to implement the method (for example, TinyBuilder). I think the theory is probably that an implementation of Receiver is required to implement one of the two append() methods but not both; but that can't be checked at compile time so it definitely risks a run-time failure if there's some path that hasn't been properly tested.

Perhaps a better solution would be to define the 1-argument append() method only on Outputter and not on Receiver.

Simplifying some of our complex class hierarchies is certainly desirable: these things give a lot of trouble when transpiling to C#.

RE: XdmValue.toString giving UnsupportedOperationException, perhaps through default Receiver implementation: problem only occurs in CheerpJ environment - Added by Martin Honnen 7 months ago

The CheerpJ team has resolved the issue which caused Saxon to throw the UnsupportedOperationException in XdmValue.toString, so it was indeed a problem in their implementation. Now XPath evaluation in https://witty-dune-0fb497610.3.azurestaticapps.net/ finally displays results which are a sequence of more than one item :).

    (1-3/3)

    Please register to reply