Useful utilities for debugging JavaScript event handlers

When working on a large web application including numerous libraries and frameworks (say knockout.js, jQuery UI, and Bootstrap), it can be difficult to figure out what originally caused a function to be bound to various events (be they browser native or user-defined). These 3 remarkable little utilities all help to find out exactly that:

jQuery._data(document, “events”)
This is a piece of internal jQuery API (so shouldn’t be relied on in production) that will list all events attached to the element provided as the first argument:jQuery eventsNote that the first argument should be an object conforming to the Element or Document DOM interfaces, rather than a jQuery object or selector (although the raw DOM object can be retrieved using a jQuery selector and dereferencing the first item of the jQuery “array”: $(“p:first”)[0])

getEventListeners()
Specific to Safari and Chrome, getEventListeners() provides much the same functionality as the jQuery ._data() call above, but without the dependency on jQuery:
getEventListeners

monitorEvents()
Again specific to Safari and Chrome, monitorEvents() takes either one or two arguments, the first of which is the Element or Document DOM object to monitor, and the second (optional) argument is the type of event to listen for, presently limited to one of four strings: “mouse”, “key”, “touch”, or “control”. On executing monitorEvents(document) in the console, all future events applying to that element are logged, optionally filtered by event type:
monitorEvents
Calling unmonitorEvents() on the same DOM object will stop logging to the console.

Parsing external DTDs with Spring 4.x Jaxb2Marshaller

Having recently upgraded a fairly sizeable Spring project to Spring 4.1.7, I uncovered an issue in which, after the upgrade, a class that talks to an external XML API was failing with the following stack trace:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.richpollock.blog.ExampleClass];
nested exception is org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception;
nested exception is javax.xml.bind.UnmarshalException
 - with linked exception:
	[org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.]
	at org.springframework.http.converter.xml.MarshallingHttpMessageConverter.readFromSource(MarshallingHttpMessageConverter.java:134)
	at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.readInternal(AbstractXmlHttpMessageConverter.java:61)
	...

As with most exceptions thrown by large libraries such as Spring, there’s an underlying exception that’s been thrown, wrapped and rethrown. And, as with most exceptions thrown by JAXB, there are also a lot of linked exceptions, which in this case originate from a SAXParseException thrown by Xerces (a JSR 206-compliant, fully-conforming XML Schema 1.0 processor).

In this instance, the error is thrown by the PrologDispatcher (née PrologDriver), a nested class that forms part of Xerces’ XMLDocumentScannerImpl class. That the exception is being thrown in the XML prolog shows that the failure occurs before the start tag of the XML document is reached. Specifically, the following line in PrologDispatcher is responsible for throwing the exception:

switch(fScannerState){
...
case SCANNER_STATE_DOCTYPE: {
	if (fDisallowDoctype) {
		reportFatalError("DoctypeNotAllowed", null);
	}
...

The difficulty is that the code is buried way down in the inner workings of the XML parser, which in this case, wasn’t instantiated by us in the first place. Indeed, the last code that was under our direct control was a call to the getForObject() method on an autowired RestTemplate instance. Regardless, the fDisallowDoctype check in PrologDispatcher is reminiscent of the problem reported in the initial stack trace: “DOCTYPE is disallowed when the feature “http://apache.org/xml/features/disallow-doctype-decl” set to true.”

As the name suggests, the disallow-doctype-decl feature prevents an XML document from being parsed if it contains a document type definition (DTD; specified using the DOCTYPE declaration in the XML). Along with the related FEATURE_SECURE_PROCESSING option, this can prevent both XML eXternal Entity (XXE) attacks, which can expose local file content, and XML Entity Expansion (XEE) attacks, which can result in denial of service. As such, the disallow-doctype-decl feature shouldn’t be disabled without giving due consideration to the security implications.

With that said, a bit of searching around reveals a few options for how the disallow-doctype-decl feature can be configured, but they depend on having direct access to the SAXParserFactory instance, setting and unsetting System properties, setting a JRE-wide jaxp.properties file, or passing command-line flags to the JVM. None of these are particularly desirable (or easily achievable).

So the next step was to identify the calls between the Spring RestTemplate (over which we have direct control in code) and the XML parsing code that’s throwing the exception. Thankfully, in this instance, we have control of the RestTemplate bean configuration in the application context as follows:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg ref="httpClientFactory"/>

    <property name="messageConverters"> 
        <list> 
            <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> 
                <property name="marshaller" ref="jaxbMarshaller"/> 
                <property name="unmarshaller" ref="jaxbMarshaller"/> 
            </bean> 
        </list> 
    </property>
</bean>

The jaxbMarshaller bean (as referenced above) is also configured in the application context as an instance of Jaxb2Marshaller:

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

    <property name="classesToBeBound"> 
        <list> 
         ...    
        </list> 
    </property>

</bean>

Having initially tried to set the “http://apache.org/xml/features/disallow-doctype-decl” option to “false” through the setMarshallerProperties() method on Jaxb2Marshaller, I subsequently noticed the setSupportDtd property, which “Indicates whether DTD parsing should be supported.” This resolves the issue and, ultimately, the fix comes down to configuring the Jaxb2Marshaller bean with the following option:

<property name="supportDtd" value="true" />

Note that supportDtd can also be set to true by setting the Jaxb2Marshaller processExternalEntities property to true; the difference being that the latter both allows parsing of XML with a DOCTYPE declaration and processing of external entities referenced from the XML document. Jaxb2Marshaller ultimately uses the (logical complement of the) supportDtd option to set the “http://apache.org/xml/features/disallow-doctype-decl” feature on whichever XMLReader implementation is returned from XMLReaderFactory. By default, this is the class that the JVM-instance-wide org.xml.sax.driver property is set to, the class specified in META-INF/services/org.xml.sax.driver or, as a fallback, com.sun.org.apache.xerces.internal.parsers.SAXParser.

For security reasons, it would make sense to configure 2 Jaxb2Marshaller instances, one with DOCTYPE support enabled and one without, using the instance with DOCTYPE support only where it’s absolutely necessary and the XML source is trusted.

Ensuring that spreadsheets created by xlsx4j can be opened by Quick Look and Numbers

Following on from an earlier post on simplifying the addition of text-only cells to an Excel worksheet using xlsx4j, here’s a brief addendum that allows Apple’s Quick Look to preview the spreadsheet and for it to opened in Numbers (Apple’s spreadsheet package for OS X and iOS).

In short, Excel’s requirement for a “minimum viable OOXML spreadsheet” seems to be less stringent than Apple’s and, as such, following the steps outlined in the previous post would result in a spreadsheet that could be opened in Excel, but not in Quick Look or Numbers.

Thankfully, the fix is quite straightforward; it transpires that Apple’s software can’t open the spreadsheet if the /xl/styles.xml “part” is missing from the spreadsheet. Even an empty stylesheet is sufficient:

SpreadsheetMLPackage pkg = SpreadsheetMLPackage.createPackage();
WorksheetPart sheet = pkg.createWorksheetPart(new PartName("/xl/worksheets/sheet1.xml"), "Sheet 1", 1);
SheetData sheetData = sheet.getContents().getSheetData();

// Add a minimal stylesheet to the package
Styles styles = new Styles(new PartName("/xl/styles.xml"));
CTStylesheet ss = Context.getsmlObjectFactory().createCTStylesheet();
styles.setJaxbElement(ss);
pkg.getWorkbookPart().addTargetPart(styles);

Row titleRow = Context.getsmlObjectFactory().createRow();
titleRow.setHt(22.0);
titleRow.setCustomHeight(Boolean.TRUE);
Cell headerCell = this.newCellWithInlineString("Sheet 1 Heading");

titleRow.getC().add(headerCell);
sheetData.getRow().add(titleRow);

pkg.save(new File("Example.xlsx"));

See the previous post for the implementation of the newCellWithInlineString method. It’s also worth noting that the getJaxbElement() method on the WorksheetPart class has been deprecated since the last post and replaced with getContents(), as above.