Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8151585

javax.xml.parsers.DocumentBuilder.parse(java.io.File file) does not allways close file

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.8.0_74"
      Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
      Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [version 6.1.7601]

      A DESCRIPTION OF THE PROBLEM :
      Test 1:
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(java.io.File file).
      Try to delete the file whith java.io.File.delete(file), it does not work.

      Test 2:
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(java.io.File file).
      Set the DocumentBuilder you used to null
      Set the resulting Document to null
      Call System.gc()
      delete the file whith java.io.File.delete(file), it works

      Test 3
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(InputStream inputStream).
      Close the file with inputStream.close(), it works

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Test 1:
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(java.io.File file).
      Try to delete the file whith java.io.File.delete(file), it does not work.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      File deleted and File.delete() returns true.
      ACTUAL -
      File not deleted and File.delete() returns false.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      [Fatal Error] error00.xml:2:2: Le balisage du document précédant l'élément racine doit avoir un format correct.
      Parsing D:\Temp\error00.xml failed as expected.
      We could not delete D:\Temp\error00.xml
      Scenario 1: KO
      [Fatal Error] error01.xml:2:2: Le balisage du document précédant l'élément racine doit avoir un format correct.
      Parsing D:\Temp\error01.xml failed as expected.
      We could delete D:\Temp\error01.xml
      Scenario 2: OK
      [Fatal Error] :2:2: Le balisage du document précédant l'élément racine doit avoir un format correct.
      Parsing D:\Temp\error02.xml failed as expected.
      We could delete D:\Temp\error02.xml
      Scenario 3: OK


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.BufferedOutputStream;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.InputStream;
      import java.io.OutputStream;
      import java.io.IOException;
      import java.nio.charset.StandardCharsets;
      import javax.xml.parsers.DocumentBuilder;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;

      import org.xml.sax.SAXException;

      public class Parser {
        private static final String FILE_SCENARIO_1 = "D:\\Temp\\error00.xml";
        private static final String FILE_SCENARIO_2 = "D:\\Temp\\error01.xml";
        private static final String FILE_SCENARIO_3 = "D:\\Temp\\error02.xml";

        private static final String NEWLINE = System.getProperty("line.separator");

        private static final String[] ERRONEOUS_XML = {
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
          "</Document>"
        };

        private Parser() {
          super();
        }

        private static boolean writeErrFile(File file) {
          OutputStream outputStream = null;
          try {
            outputStream = new BufferedOutputStream(new FileOutputStream(file));
          } catch (IOException e) {
            System.out.println("Could not open file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          }

          try {
            for (String str : ERRONEOUS_XML) {
              str = str.concat(NEWLINE);
              outputStream.write(str.getBytes(StandardCharsets.UTF_8));
            }
          } catch (IOException e) {
            try {
              outputStream.close();
            } catch (IOException f) {
              f.addSuppressed(e);
              System.out.println("Could not write and close file " + file.getAbsolutePath());
              f.printStackTrace();
              return false;
            }

            System.out.println("Could not write file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          }
        
          try {
            outputStream.close();
          } catch (IOException e) {
            System.out.println("Could not close file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          }
        
          return true;
        }

        private static boolean parse1(File file) {
          DocumentBuilder db = null;
          
      try {
      db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      } catch (ParserConfigurationException e) {
            System.out.println("Could not create document builder.");
            e.printStackTrace();
            return false;
          }

          try {
            db.parse(file);
          } catch (IOException e) {
            System.out.println("Could not read file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          } catch (SAXException e) {
            System.out.println("Parsing " + file.getAbsolutePath() + " failed as expected.");
            return true;
          }

          System.out.println("We did not get the expected error while reading " + file.getAbsolutePath());
          return false;
        }

        private static boolean parse2(File file) {
          DocumentBuilder db = null;
          
      try {
      db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      } catch (ParserConfigurationException e) {
            System.out.println("Could not create document builder.");
            e.printStackTrace();
            return false;
          }

          try {
            db.parse(file);
          } catch (IOException e) {
            System.out.println("Could not read file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          } catch (SAXException e) {
            System.out.println("Parsing " + file.getAbsolutePath() + " failed as expected.");
            db = null;
            System.gc();
            return true;
          }

          System.out.println("We did not get the expected error while reading " + file.getAbsolutePath());
          return false;
        }

        private static boolean parse3(File file) {
          DocumentBuilder db = null;
          InputStream inputStream = null;
          
      try {
      db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      } catch (ParserConfigurationException e) {
            System.out.println("Could not create document builder.");
            e.printStackTrace();
            return false;
          }

          try {
            inputStream = new FileInputStream(file);
          } catch (IOException e) {
            System.out.println("Could open file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          }

          try {
            db.parse(inputStream);
          } catch (IOException e) {
            try {
              inputStream.close();
            } catch (IOException f) {
              f.addSuppressed(e);
              System.out.println("Could not read and close file " + file.getAbsolutePath());
              f.printStackTrace();
              return false;
            }

            System.out.println("Could not read file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          } catch (SAXException e) {
            try {
              inputStream.close();
            } catch (IOException f) {
              f.addSuppressed(e);
              System.out.println("Could not parse and close file " + file.getAbsolutePath());
              f.printStackTrace();
              return false;
            }

            System.out.println("Parsing " + file.getAbsolutePath() + " failed as expected.");
            return true;
          }

          try {
            inputStream.close();
          } catch (IOException e) {
            System.out.println("Could not close file " + file.getAbsolutePath());
            e.printStackTrace();
            return false;
          }

          System.out.println("We did not get the expected error while reading " + file.getAbsolutePath());
          return false;
        }

        private static boolean delete(File file) {
          if (file.delete()) {
            System.out.println("We could delete " + file.getAbsolutePath());
            return true;
          } else {
            System.out.println("We could not delete " + file.getAbsolutePath());
            return false;
          }
        }

        private static void scenario1() {
          File file = new File(FILE_SCENARIO_1);

          if (writeErrFile(file) && parse1(file) && delete(file)) {
            System.out.println("Scenario 1: OK");
          } else {
            System.out.println("Scenario 1: KO");
          }
        }

        private static void scenario2() {
          File file = new File(FILE_SCENARIO_2);

          if (writeErrFile(file) && parse2(file) && delete(file)) {
            System.out.println("Scenario 2: OK");
          } else {
            System.out.println("Scenario 2: KO");
          }
        }

        private static void scenario3() {
          File file = new File(FILE_SCENARIO_3);

          if (writeErrFile(file) && parse3(file) && delete(file)) {
            System.out.println("Scenario 3: OK");
          } else {
            System.out.println("Scenario 3: KO");
          }
        }

        public static void main(String[] args) {
          scenario1();
          scenario2();
          scenario3();
        }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Test 2:
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(java.io.File file).
      Set the DocumentBuilder you used to null
      Set the resulting Document to null
      Call System.gc()
      delete the file whith java.io.File.delete(file), it works

      Test 3
      Parse an erroneous xml file with javax.xml.parsers.DocumentBuilder.parse(InputStream inputStream).
      Close the file with inputStream.close(), it works

            joehw Joe Wang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: