Duplicate :
|
FULL PRODUCT VERSION : java version "1.6.0_26" Java(TM) SE Runtime Environment (build 1.6.0_26-b03) Java HotSpot(TM) Client VM (build 20.1-b02, mixed mode, sharing) also java version "1.7.0" Java(TM) SE Runtime Environment (build 1.7.0-b147) Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing) ADDITIONAL OS VERSION INFORMATION : Microsoft Windows XP [Version 5.1.2600] A DESCRIPTION OF THE PROBLEM : When javax.xml.parsers.DocumentBuilder.parse(File) is called and a SAXException is thrown in the ErrorHandler, the file is not closed. This bug is present in java 1.6.0_26 and java 1.7.0. This bug is not present in java 1.5.0_22. REGRESSION. Last worked in version 5.0 STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : 1. Use an instance of javax.xml.parsers.DocumentBuilder to parse a java.io.File that contains XML that is not well-formed. 2. Check that the XML file is still open (e.g. by trying to delete it). EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - The parse will cause a SAXException to be thrown. Using a finally block it should be possible to delete the XML input file. ACTUAL - The XML input file could not be deleted. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class Main { private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; private static class SimpleErrorHandler implements ErrorHandler { private final boolean rethrow; public SimpleErrorHandler( boolean rethrow ) { this.rethrow = rethrow; } public void error( SAXParseException ex ) throws SAXException { conditionallyThrow( ex ); } public void fatalError( SAXParseException ex ) throws SAXException { conditionallyThrow( ex ); } public void warning( SAXParseException ex ) throws SAXException { conditionallyThrow( ex ); } private void conditionallyThrow( SAXException ex ) throws SAXException { if(this.rethrow) { throw ex; } } } // The output should be: // // File "D:\work\Parse\temp.xml" deleted. // File "D:\work\Parse\temp.xml" deleted. // // but in java 1.6.0_26 and java 1.7.0 the output is: // // File "D:\work\Parse\temp.xml" deleted. // File "D:\work\Parse\temp.xml" not deleted. public static void main( String[] args ) throws Exception { Main main = new Main(); main.test( false ); main.test( true ); } private void close( Closeable closeable ) { if(closeable != null) { try { closeable.close(); } catch(IOException ex) { ex.printStackTrace(); } } } private File getFile() throws IOException { File fileIn = new File( "save.xml" ); File fileOut = new File( "temp.xml" ); FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream( fileIn ); out = new FileOutputStream( fileOut ); byte[] buffer = new byte[ 4096 ]; int read; while(( read = in.read( buffer ) ) != -1) { out.write( buffer, 0, read ); } } finally { close( out ); close( in ); } return fileOut; } private void test( boolean rethrow ) throws ParserConfigurationException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setAttribute( JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA ); factory.setNamespaceAware( true ); factory.setValidating( true ); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler( new SimpleErrorHandler( rethrow ) ); File file = getFile(); try { builder.parse( file ); } catch(SAXException ex) { // System.out.println( ex ); } finally { System.out.println( "File \"" + file.getAbsolutePath() + "\"" + ( file.delete() ? " deleted." : " not deleted." ) ); } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Use DocumentBuilder.parse(InputStream) and then close the input stream in a finally block.