Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I unlock a file locked by JAXB's unmarhsaller

Tags:

jaxb

I'm unmarshalling an XML file with JAXB w/Java 1.7.0_03 on Windows 7 x64 using the following code:

 try (InputStream xsdStream = ConfigurationService.class.getClassLoader().getResourceAsStream(CONFIG_XSD_FILE_NAME)) {
            configFile = new File(configFilePath);
            if (configFile.exists()) {
                context = JAXBContext.newInstance(Config.class);
                Unmarshaller unMarshaller = context.createUnmarshaller();

                SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                StreamSource xsdStreamSource = new StreamSource(xsdStream);
                Schema schema = sf.newSchema(xsdStreamSource);

                unMarshaller.setSchema(schema);
                Object xmlObject = Config.class.cast(unMarshaller.unmarshal(configFile));
                myConfig = (Config) xmlObject;
            } else {
                log.severe(configFile.getAbsolutePath() + " does not exist, can not parse configuration info from it.");
            }
  }

Code which calls this method subsequently deletes the XML file.

The XML file will properly delete if unmarhalling is successful. However, if the above code throws and Exception, eg. a SAXException, the XML file remains locked indefinitely and the calling code is not able to delete it with File.delete().

This feels like JAXB is not closing the resource/file in this case. Is it my responsibility to do that somehow or is this a bug?

Reviewing the javadoc for Unmarshaller did not shed any light on this and Googling this issue revealed this old, unanswered question from 2008.

like image 308
NBW Avatar asked Feb 08 '13 04:02

NBW


1 Answers

SHORT ANSWER

The behaviour you have described sounds like a bug in the JAXB reference implementation. You can open a ticket using the link below:

  • http://java.net/jira/browse/JAXB/

Work Around

Instead of unmarshalling from a File you can unmarshal from a FileInputStream and control that it is closed correctly yourself after unmarshalling.


LONG ANSWER

I have not been able to reproduce the issue that you are seeing. I have included what I have tried below. I am using JDK 1.7.0_07 x64 for the Mac.

Configuration Service

Most of the code below is copied from your question. I have added the call to delete the input file and then output if the file still exists.

package forum14765898;

import java.io.*;

import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;

public class ConfigurationService {

    private static final String CONFIG_XSD_FILE_NAME = "forum14765898/schema.xsd";

    public static void main(String[] args) throws Exception {
        File configFile = null;
        String configFilePath = "src/forum14765898/input.xml";
        JAXBContext context;
        Config myConfig;

        try (InputStream xsdStream = ConfigurationService.class.getClassLoader().getResourceAsStream(CONFIG_XSD_FILE_NAME)) {
            configFile = new File(configFilePath);
            if (configFile.exists()) {
                context = JAXBContext.newInstance(Config.class);
                Unmarshaller unMarshaller = context.createUnmarshaller();

                SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                StreamSource xsdStreamSource = new StreamSource(xsdStream);
                Schema schema = sf.newSchema(xsdStreamSource);

                unMarshaller.setSchema(schema);
                Object xmlObject = Config.class.cast(unMarshaller.unmarshal(configFile));
                myConfig = (Config) xmlObject;
            } else {
                //log.severe(configFile.getAbsolutePath() + " does not exist, can not parse configuration info from it.");
            }
        } catch(Exception e) {
            e.printStackTrace(System.out);
        }

        configFile.delete();
        System.out.println(configFile.exists());

    }

}

schema.xsd

Below is the simple XML schema that I am using.

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
    <element name="config">
        <complexType>
            <sequence>
                <element name="bar" type="int"/>
            </sequence>
        </complexType>
    </element>
</schema>

input.xml

Below is the XML input. The bar element is not valid according to the XML schema. When a Schema is set on the Unmarshaller this document will be enough to cause an Exception to be thrown while performing an unmarshal operation.

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <bar>INVALID</bar>
</config>

Config

package forum14765898;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Config {

    public int bar;

}

Output

Below is output from running the demo code. It shows both the validation exception and on the last line we see that the XML file was successfully deleted as it no longer exists.

javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; systemId: file:/Users/bdoughan/Scratch/src/forum14765898/input.xml; lineNumber: 3; columnNumber: 23; cvc-datatype-valid.1.2.1: 'INVALID' is not a valid value for 'integer'.]
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:512)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:209)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189)
    at forum14765898.ConfigurationService.main(ConfigurationService.java:31)
Caused by: org.xml.sax.SAXParseException; systemId: file:/Users/bdoughan/Scratch/src/forum14765898/input.xml; lineNumber: 3; columnNumber: 23; cvc-datatype-valid.1.2.1: 'INVALID' is not a valid value for 'integer'.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:453)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3232)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(XMLSchemaValidator.java:3147)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(XMLSchemaValidator.java:3057)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(XMLSchemaValidator.java:2135)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(XMLSchemaValidator.java:854)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(ValidatorHandlerImpl.java:579)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.endElement(ValidatingUnmarshaller.java:91)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:143)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1742)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2900)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
    ... 6 more
false
like image 197
bdoughan Avatar answered Nov 13 '22 01:11

bdoughan