diff --git a/src/main/java/com/github/pjfanning/xlsx/StreamingReader.java b/src/main/java/com/github/pjfanning/xlsx/StreamingReader.java index 526c22f6..63443395 100644 --- a/src/main/java/com/github/pjfanning/xlsx/StreamingReader.java +++ b/src/main/java/com/github/pjfanning/xlsx/StreamingReader.java @@ -1,5 +1,6 @@ package com.github.pjfanning.xlsx; +import com.github.pjfanning.xlsx.exceptions.CheckedReadException; import com.github.pjfanning.xlsx.exceptions.OpenException; import com.github.pjfanning.xlsx.exceptions.ParseException; import com.github.pjfanning.xlsx.exceptions.ReadException; @@ -545,7 +546,9 @@ public Builder setFullFormatRichText(boolean fullFormatRichText) { * * @param is input stream to read in * @return A {@link Workbook} that can be read from - * @throws com.github.pjfanning.xlsx.exceptions.ReadException if there is an issue reading the stream + * @throws OpenException if there is an issue opening the file + * @throws ReadException if there is an issue reading the file + * @throws ParseException if there is an issue parsing the XML in the file */ public Workbook open(InputStream is) throws OpenException, ReadException, ParseException { StreamingWorkbookReader workbookReader = new StreamingWorkbookReader(this); @@ -559,13 +562,50 @@ public Workbook open(InputStream is) throws OpenException, ReadException, ParseE * * @param file file to read in * @return built streaming reader instance - * @throws com.github.pjfanning.xlsx.exceptions.OpenException if there is an issue opening the file - * @throws com.github.pjfanning.xlsx.exceptions.ReadException if there is an issue reading the file + * @throws OpenException if there is an issue opening the file + * @throws ReadException if there is an issue reading the file + * @throws ParseException if there is an issue parsing the XML in the file */ public Workbook open(File file) throws OpenException, ReadException, ParseException { StreamingWorkbookReader workbookReader = new StreamingWorkbookReader(this); workbookReader.init(file); return new StreamingWorkbook(workbookReader); } + + /** + * Reads a given {@code InputStream} and returns a new + * instance of {@code Workbook}. Due to Apache POI + * limitations, a temporary file must be written in order + * to create a streaming iterator. This process will use + * the same buffer size as specified in {@link #bufferSize(int)}. + * + * @param is input stream to read in + * @return A {@link Workbook} that can be read from + * @throws IOException if an error occurs while opening the file + * @throws CheckedReadException if an error occurs while reading the file + */ + public Workbook openWithCheckedExceptions(InputStream is) throws IOException, CheckedReadException { + StreamingWorkbookReader workbookReader = new StreamingWorkbookReader(this); + workbookReader.initWithCheckedExceptions(is); + return new StreamingWorkbook(workbookReader); + } + + /** + * Reads a given {@code InputStream} and returns a new + * instance of {@code Workbook}. Due to Apache POI + * limitations, a temporary file must be written in order + * to create a streaming iterator. This process will use + * the same buffer size as specified in {@link #bufferSize(int)}. + * + * @param file file to read in + * @return A {@link Workbook} that can be read from + * @throws IOException if an error occurs while opening the file + * @throws CheckedReadException if an error occurs while reading the file + */ + public Workbook openWithCheckedExceptions(File file) throws IOException, CheckedReadException { + StreamingWorkbookReader workbookReader = new StreamingWorkbookReader(this); + workbookReader.initWithCheckedExceptions(file); + return new StreamingWorkbook(workbookReader); + } } } diff --git a/src/main/java/com/github/pjfanning/xlsx/exceptions/CheckedReadException.java b/src/main/java/com/github/pjfanning/xlsx/exceptions/CheckedReadException.java new file mode 100644 index 00000000..80af8abe --- /dev/null +++ b/src/main/java/com/github/pjfanning/xlsx/exceptions/CheckedReadException.java @@ -0,0 +1,33 @@ +package com.github.pjfanning.xlsx.exceptions; + +/** + * A checked exception that is thrown if there is a problem reading the Excel file. + * + *

+ * To avoid adding a large number of new checked exceptions to the method signatures, + * this exception is generic. Any read issue will throw this exception. You can look call + * {@link #getCause()} to get the underlying exception will is likely to be one of the more specific + * legacy exceptions that implement {@link com.github.pjfanning.xlsx.exceptions.ExcelRuntimeException}. + *

+ * + * @see ReadException + * @since 4.4.0 + */ +public class CheckedReadException extends ExcelCheckedException { + + public CheckedReadException() { + super(); + } + + public CheckedReadException(String msg) { + super(msg); + } + + public CheckedReadException(Exception e) { + super(e); + } + + public CheckedReadException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/src/main/java/com/github/pjfanning/xlsx/exceptions/ExcelCheckedException.java b/src/main/java/com/github/pjfanning/xlsx/exceptions/ExcelCheckedException.java new file mode 100644 index 00000000..bd0c33a5 --- /dev/null +++ b/src/main/java/com/github/pjfanning/xlsx/exceptions/ExcelCheckedException.java @@ -0,0 +1,25 @@ +package com.github.pjfanning.xlsx.exceptions; + +/** + * A parent class for all the excel-streaming-reader specific Checked Exceptions (i.e. not Runtime Exceptions). + * + * @since 4.4.0 + */ +public class ExcelCheckedException extends Exception { + + protected ExcelCheckedException() { + super(); + } + + protected ExcelCheckedException(String msg) { + super(msg); + } + + protected ExcelCheckedException(Exception e) { + super(e); + } + + protected ExcelCheckedException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/src/main/java/com/github/pjfanning/xlsx/exceptions/ReadException.java b/src/main/java/com/github/pjfanning/xlsx/exceptions/ReadException.java index 5ff14a72..0c9233cf 100644 --- a/src/main/java/com/github/pjfanning/xlsx/exceptions/ReadException.java +++ b/src/main/java/com/github/pjfanning/xlsx/exceptions/ReadException.java @@ -1,5 +1,11 @@ package com.github.pjfanning.xlsx.exceptions; +/** + * A Runtime Exception that is thrown if there is a problem reading the Excel file. + * This is used in APIs where the method is unable to throw a checked exception. + * + * @see CheckedReadException + */ public class ReadException extends ExcelRuntimeException { public ReadException() { diff --git a/src/main/java/com/github/pjfanning/xlsx/impl/StreamingWorkbookReader.java b/src/main/java/com/github/pjfanning/xlsx/impl/StreamingWorkbookReader.java index 58a363a3..a9c0bf6d 100644 --- a/src/main/java/com/github/pjfanning/xlsx/impl/StreamingWorkbookReader.java +++ b/src/main/java/com/github/pjfanning/xlsx/impl/StreamingWorkbookReader.java @@ -4,6 +4,7 @@ import com.github.pjfanning.poi.xssf.streaming.TempFileSharedStringsTable; import com.github.pjfanning.xlsx.SharedStringsImplementationType; import com.github.pjfanning.xlsx.StreamingReader.Builder; +import com.github.pjfanning.xlsx.exceptions.CheckedReadException; import com.github.pjfanning.xlsx.exceptions.ExcelRuntimeException; import com.github.pjfanning.xlsx.exceptions.MissingSheetException; import com.github.pjfanning.xlsx.exceptions.NotSupportedException; @@ -73,8 +74,121 @@ public StreamingWorkbookReader(Builder builder) { * @throws OpenException if an error occurs while opening the file * @throws ReadException if an error occurs while reading the file * @throws ParseException if an error occurs while parsing the file + * @see #initWithCheckedExceptions(InputStream) */ public void init(InputStream is) throws OpenException, ReadException, ParseException { + try { + _init(is); + } catch(SAXException| XMLStreamException e) { + throw new ParseException("Failed to parse stream", e); + } catch(IOException e) { + throw new OpenException("Failed to open stream", e); + } catch(UnsupportedFileFormatException e) { + throw new ReadException("Unsupported File Format (only xlsx files are supported)", e); + } catch(GeneralSecurityException e) { + throw new ReadException("Unable to read workbook - Decryption failed", e); + } catch (ExcelRuntimeException e) { + throw e; + } catch(OpenXML4JException | RuntimeException e) { + throw new ReadException("Unable to read workbook", e); + } + } + + /** + * Initializes the reader with the given input stream. + * @param is the input stream to read from + * @throws IOException if an error occurs while opening the file + * @throws CheckedReadException if an error occurs while reading the file + * @since 4.3.0 + */ + public void initWithCheckedExceptions(InputStream is) throws IOException, CheckedReadException { + try { + _init(is); + } catch(SAXException | XMLStreamException e) { + throw new CheckedReadException("Failed to parse stream", e); + } catch(IOException e) { + throw e; + } catch(UnsupportedFileFormatException e) { + throw new CheckedReadException("Unsupported File Format (only xlsx files are supported)", e); + } catch(GeneralSecurityException e) { + throw new CheckedReadException("Unable to read workbook - Decryption failed", e); + } catch(OpenXML4JException | RuntimeException e) { + throw new CheckedReadException("Unable to read workbook", e); + } + } + + /** + * Initializes the reader with the given input stream. + * @param f the file to read from + * @throws OpenException if an error occurs while opening the file + * @throws ReadException if an error occurs while reading the file + * @throws ParseException if an error occurs while parsing the file + * @see #initWithCheckedExceptions(File) + * @since 4.3.0 + */ + public void init(File f) throws OpenException, ReadException, ParseException { + try { + _init(f); + } catch(SAXException | XMLStreamException e) { + IOUtils.closeQuietly(pkg); + throw new ParseException("Failed to parse file", e); + } catch(IOException e) { + IOUtils.closeQuietly(pkg); + throw new OpenException("Failed to open file", e); + } catch(UnsupportedFileFormatException e) { + IOUtils.closeQuietly(pkg); + throw new ReadException("Unsupported File Format (only xlsx files are supported)", e); + } catch(OpenXML4JException e) { + IOUtils.closeQuietly(pkg); + throw new ReadException("Unable to read workbook", e); + } catch(GeneralSecurityException e) { + IOUtils.closeQuietly(pkg); + throw new ReadException("Unable to read workbook - Decryption failed", e); + } catch(ExcelRuntimeException e) { + IOUtils.closeQuietly(pkg); + throw e; + } catch(RuntimeException e) { + IOUtils.closeQuietly(pkg); + throw new ReadException("Unable to read workbook", e); + } + } + + /** + * Initializes the reader with the given input stream. + * @param f the file to read from + * @throws IOException if an error occurs while opening the file + * @throws CheckedReadException if an error occurs while reading the file + * @since 4.3.0 + */ + public void initWithCheckedExceptions(File f) throws IOException, CheckedReadException { + try { + _init(f); + } catch(SAXException | XMLStreamException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException("Failed to parse file", e); + } catch(IOException e) { + IOUtils.closeQuietly(pkg); + throw e; + } catch(UnsupportedFileFormatException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException("Unsupported File Format (only xlsx files are supported)", e); + } catch(OpenXML4JException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException("Unable to read workbook", e); + } catch(GeneralSecurityException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException("Unable to read workbook - Decryption failed", e); + } catch(ExcelRuntimeException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException(e.getMessage(), e); + } catch(RuntimeException e) { + IOUtils.closeQuietly(pkg); + throw new CheckedReadException("Unable to read workbook", e); + } + } + + private void _init(InputStream is) throws OpenXML4JException, XMLStreamException, + GeneralSecurityException, IOException, SAXException { if (builder.avoidTempFiles()) { try { if(builder.getPassword() != null) { @@ -84,18 +198,9 @@ public void init(InputStream is) throws OpenException, ReadException, ParseExcep pkg = OPCPackage.open(is); } loadPackage(pkg); - } catch(SAXException e) { - IOUtils.closeQuietly(pkg); - throw new ParseException("Failed to parse stream", e); - } catch(IOException e) { + } catch(Exception e) { IOUtils.closeQuietly(pkg); - throw new OpenException("Failed to open stream", e); - } catch(GeneralSecurityException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unable to read workbook - Decryption failed", e); - } catch(OpenXML4JException | XMLStreamException | RuntimeException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unable to read workbook", e); + throw e; } } else { File f = null; @@ -104,35 +209,19 @@ public void init(InputStream is) throws OpenException, ReadException, ParseExcep if (log.isDebugEnabled()) { log.debug("Created temp file [{}]", f.getAbsolutePath()); } - init(f); + _init(f); tmp = f; - } catch(OpenException | ReadException e) { + } catch(Exception e) { if (f != null && !f.delete()) { log.debug("failed to delete temp file"); } throw e; - } catch(UnsupportedFileFormatException e) { - if (f != null && !f.delete()) { - log.debug("failed to delete temp file"); - } - throw new ReadException("Unsupported File Format (only xlsx files are supported)", e); - } catch(IOException | RuntimeException e) { - if (f != null && !f.delete()) { - log.debug("failed to delete temp file"); - } - throw new ReadException("Unable to read input stream", e); } } } - /** - * Initializes the reader with the given input stream. - * @param f the file to read from - * @throws OpenException if an error occurs while opening the file - * @throws ReadException if an error occurs while reading the file - * @throws ParseException if an error occurs while parsing the file - */ - public void init(File f) throws OpenException, ReadException, ParseException { + private void _init(File f) throws OpenXML4JException, XMLStreamException, + GeneralSecurityException, IOException, SAXException { try { if(builder.getPassword() != null) { POIFSFileSystem poifs = new POIFSFileSystem(f); @@ -141,27 +230,9 @@ public void init(File f) throws OpenException, ReadException, ParseException { pkg = OPCPackage.open(f); } loadPackage(pkg); - } catch(SAXException e) { - IOUtils.closeQuietly(pkg); - throw new ParseException("Failed to parse file", e); - } catch(IOException e) { - IOUtils.closeQuietly(pkg); - throw new OpenException("Failed to open file", e); - } catch(UnsupportedFileFormatException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unsupported File Format (only xlsx files are supported)", e); - } catch(OpenXML4JException | XMLStreamException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unable to read workbook", e); - } catch(GeneralSecurityException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unable to read workbook - Decryption failed", e); - } catch(ExcelRuntimeException e) { + } catch(Exception e) { IOUtils.closeQuietly(pkg); throw e; - } catch(RuntimeException e) { - IOUtils.closeQuietly(pkg); - throw new ReadException("Unable to read workbook", e); } }