JDK-7077542 : javax.xml.parsers.DocumentBuilder.parse(File) does not always close file.
  • Type: Bug
  • Component: xml
  • Sub-Component: org.w3c.dom
  • Affected Version: 6u26
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2011-08-10
  • Updated: 2014-04-11
  • Resolved: 2014-04-11
Related Reports
Duplicate :  
Description
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.