You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2021/08/25 11:51:25 UTC

[sling-org-apache-sling-feature-cpconverter] branch master updated: SLING-10705 : Improve exception handling and error reporting

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git


The following commit(s) were added to refs/heads/master by this push:
     new a5d17dd  SLING-10705 : Improve exception handling and error reporting
a5d17dd is described below

commit a5d17dd7d19983a5b16e54dd971cd1d9ec40d3e2
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Aug 25 13:51:19 2021 +0200

    SLING-10705 : Improve exception handling and error reporting
---
 .../ContentPackage2FeatureModelConverter.java      |   8 +-
 ...onEntryHandler.java => ConverterException.java} |  34 ++++---
 .../AbstractConfigurationEntryHandler.java         |   8 +-
 .../handlers/AbstractContentPackageHandler.java    |   6 +-
 .../handlers/AbstractPolicyEntryHandler.java       |  44 +++++----
 .../handlers/AbstractUserEntryHandler.java         |   4 +-
 .../cpconverter/handlers/BundleEntryHandler.java   | 102 +++++++++++----------
 .../handlers/ConfigurationEntryHandler.java        |   4 +-
 .../handlers/ContentPackageEntryHandler.java       |   8 +-
 .../feature/cpconverter/handlers/EntryHandler.java |   6 +-
 .../handlers/JsonConfigurationEntryHandler.java    |   4 +-
 .../handlers/NodeTypesEntryHandler.java            |   4 +-
 .../PropertiesConfigurationEntryHandler.java       |   4 +-
 .../handlers/SlingInitialContentBundleHandler.java |   6 +-
 .../VersionResolverContentPackageEntryHandler.java |   4 +-
 .../cpconverter/shared/AbstractJcrNodeParser.java  |  15 ++-
 .../vltpkg/BaseVaultPackageScanner.java            |  10 +-
 .../vltpkg/RecollectorVaultPackageScanner.java     |   4 +-
 .../cpconverter/vltpkg/VaultPackageAssembler.java  |   3 +-
 .../org/apache/sling/feature/cpconverter/Util.java |   9 +-
 .../handlers/BundleEntryHandlerGAVTest.java        |   3 +-
 .../handlers/ConfigEntryHandlerTest.java           |   6 +-
 22 files changed, 179 insertions(+), 117 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java b/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java
index a02f1a5..b0a5232 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java
@@ -350,7 +350,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne
         idPackageMapping.remove(pack.getId());
     }
 
-    public void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage vaultPackage, boolean isEmbeddedPackage) throws Exception {
+    public void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage vaultPackage, boolean isEmbeddedPackage) throws IOException, ConverterException {
         requireNonNull(path, "Impossible to process a null vault package");
         requireNonNull(vaultPackage, "Impossible to process a null vault package");
 
@@ -392,7 +392,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne
     }
 
     private @NotNull VaultPackage processContentPackageArchive(@NotNull VaultPackageAssembler assembler,
-                                             @Nullable String runMode) throws Exception {
+                                             @Nullable String runMode) throws IOException, ConverterException {
         File contentPackageArchive = assembler.createPackage();
 
         VaultPackage vaultPackage = open(contentPackageArchive);
@@ -470,7 +470,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne
         return subContentPackages.containsValue(path);
     }
 
-    private void process(@NotNull String entryPath, @NotNull Archive archive, @Nullable Entry entry) throws Exception {
+    private void process(@NotNull String entryPath, @NotNull Archive archive, @Nullable Entry entry) throws IOException, ConverterException {
         if (resourceFilter != null && resourceFilter.isFilteredOut(entryPath)) {
             throw new IllegalArgumentException("Path '"
                     + entryPath
@@ -497,7 +497,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne
     }
 
     @Override
-    protected void onFile(@NotNull String entryPath, @NotNull Archive archive, @NotNull Entry entry) throws Exception {
+    protected void onFile(@NotNull String entryPath, @NotNull Archive archive, @NotNull Entry entry) throws IOException, ConverterException {
         process(entryPath, archive, entry);
     }
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/ConverterException.java
similarity index 54%
copy from src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java
copy to src/main/java/org/apache/sling/feature/cpconverter/ConverterException.java
index a32e71a..688d071 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/ConverterException.java
@@ -14,24 +14,28 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.sling.feature.cpconverter.handlers;
+package org.apache.sling.feature.cpconverter;
 
-import java.io.InputStream;
-import java.util.Dictionary;
-
-import org.apache.felix.cm.file.ConfigurationHandler;
-import org.jetbrains.annotations.NotNull;
-
-public final class ConfigurationEntryHandler extends AbstractConfigurationEntryHandler {
+/**
+ * A converter exception is thrown when the conversion fails due to errors/problems
+ * in the converted source package(s).
+ */
+public class ConverterException extends Exception {
 
-    public ConfigurationEntryHandler() {
-        super("config");
+    /**
+     * Create a new exception
+     * @param message A message to be prevented to the user of the tool
+     */
+    public ConverterException(final String message) {
+        super(message);
     }
 
-    @Override
-    @SuppressWarnings("unchecked")
-    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception {
-        return ConfigurationHandler.read(input);
+    /**
+     * Create a new exception
+     * @param message A message to be prevented to the user of the tool
+     * @param cause The cause
+     */
+    public ConverterException(final String message, final Throwable cause) {
+        super(message, cause);
     }
-
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
index 8b02197..2d2daf8 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Dictionary;
 import java.util.Objects;
@@ -24,6 +25,7 @@ import java.util.regex.Matcher;
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -42,7 +44,7 @@ abstract class AbstractConfigurationEntryHandler extends AbstractRegexEntryHandl
     }
 
     @Override
-    public final void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception {
+    public final void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) throws IOException, ConverterException {
 
         Matcher matcher = getPattern().matcher(path);
         
@@ -86,7 +88,7 @@ abstract class AbstractConfigurationEntryHandler extends AbstractRegexEntryHandl
                 }
 
                 if (enforceConfigurationBelowConfigFolder && !"config".equals(matcher.group("foldername"))) {
-                    throw new IllegalStateException("OSGi configuration are only considered if placed below a folder called 'config', but the configuration at '"+ path + "' is placed outside!");
+                    throw new ConverterException("OSGi configuration are only considered if placed below a folder called 'config', but the configuration at '"+ path + "' is placed outside!");
                 }
                 
                 // there is a specified RunMode
@@ -104,6 +106,6 @@ abstract class AbstractConfigurationEntryHandler extends AbstractRegexEntryHandl
         }
     }
 
-    protected abstract @Nullable Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception;
+    protected abstract @Nullable Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws IOException, ConverterException;
 
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractContentPackageHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractContentPackageHandler.java
index abc5608..5779c2c 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractContentPackageHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractContentPackageHandler.java
@@ -18,6 +18,7 @@ package org.apache.sling.feature.cpconverter.handlers;
 
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.regex.Matcher;
@@ -28,6 +29,7 @@ import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -43,7 +45,7 @@ public abstract class AbstractContentPackageHandler extends AbstractRegexEntryHa
 
     @Override
     public final void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
+            throws IOException, ConverterException {
         logger.info("Processing sub-content package '{}'...", entry.getName());
 
         final File temporaryDir = new File(converter.getTempDirectory(), "sub-content-packages");
@@ -96,6 +98,6 @@ public abstract class AbstractContentPackageHandler extends AbstractRegexEntryHa
         logger.info("Sub-content package '{}' processing is over", entry.getName());
     }
 
-    protected abstract void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage contentPackage, @NotNull ContentPackage2FeatureModelConverter converter, boolean isEmbeddedPackage) throws Exception;
+    protected abstract void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage contentPackage, @NotNull ContentPackage2FeatureModelConverter converter, boolean isEmbeddedPackage) throws IOException, ConverterException;
 
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java
index b94f6d2..e7d4452 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java
@@ -20,15 +20,19 @@ import org.apache.commons.io.IOUtils;
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.jetbrains.annotations.NotNull;
 
 import javax.xml.transform.OutputKeys;
+import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXTransformerFactory;
 import javax.xml.transform.sax.TransformerHandler;
 import javax.xml.transform.stream.StreamResult;
+
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
@@ -46,7 +50,7 @@ abstract class AbstractPolicyEntryHandler extends AbstractRegexEntryHandler {
 
     @Override
     public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Archive.Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
+            throws IOException, ConverterException {
         String resourcePath;
         Matcher matcher = getPattern().matcher(path);
         // we are pretty sure it matches, here
@@ -60,26 +64,30 @@ abstract class AbstractPolicyEntryHandler extends AbstractRegexEntryHandler {
                                             + "' but it does not, currently");
         }
 
-        TransformerHandler handler = saxTransformerFactory.newTransformerHandler();
-        handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
-        handler.getTransformer().setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-        handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-        StringWriter stringWriter = new StringWriter();
-        handler.setResult(new StreamResult(stringWriter));
+        try {
+            TransformerHandler handler = saxTransformerFactory.newTransformerHandler();
+            handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
+            handler.getTransformer().setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+            handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            StringWriter stringWriter = new StringWriter();
+            handler.setResult(new StreamResult(stringWriter));
 
-        AbstractPolicyParser policyParser = createPolicyParser(new RepoPath(PlatformNameFormat.getRepositoryPath(resourcePath)),
-                converter.getAclManager(),
-                handler);
-        boolean hasRejectedAcls;
-        try (InputStream input = archive.openInputStream(entry)) {
-            hasRejectedAcls = policyParser.parse(input);
-        }
+            AbstractPolicyParser policyParser = createPolicyParser(new RepoPath(PlatformNameFormat.getRepositoryPath(resourcePath)),
+                    converter.getAclManager(),
+                    handler);
+            boolean hasRejectedAcls;
+            try (InputStream input = archive.openInputStream(entry)) {
+                hasRejectedAcls = policyParser.parse(input);
+            }
 
-        if (hasRejectedAcls) {
-            try (Reader reader = new StringReader(stringWriter.toString());
-                 OutputStreamWriter writer = new OutputStreamWriter(converter.getMainPackageAssembler().createEntry(path))) {
-                IOUtils.copy(reader, writer);
+            if (hasRejectedAcls) {
+                try (Reader reader = new StringReader(stringWriter.toString());
+                    OutputStreamWriter writer = new OutputStreamWriter(converter.getMainPackageAssembler().createEntry(path))) {
+                    IOUtils.copy(reader, writer);
+                }
             }
+        } catch ( final TransformerConfigurationException e) {
+            throw new IOException(e.getMessage(), e);
         }
     }
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
index f2ab658..902851a 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
@@ -21,12 +21,14 @@ import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.regex.Matcher;
@@ -41,7 +43,7 @@ abstract class AbstractUserEntryHandler extends AbstractRegexEntryHandler {
 
     @Override
     public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
+            throws IOException, ConverterException {
         Matcher matcher = getPattern().matcher(path);
         if (matcher.matches()) {
             RepoPath originalPath = new RepoPath(PlatformNameFormat.getRepositoryPath(matcher.group(1)));
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandler.java
index 1f87db6..44a3da1 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandler.java
@@ -73,6 +73,7 @@ import org.apache.sling.contentparser.json.JSONParserOptions;
 import org.apache.sling.contentparser.json.internal.JSONContentParser;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter.SlingInitialContentPolicy;
 import org.apache.sling.feature.cpconverter.artifacts.InputStreamArtifactWriter;
 import org.apache.sling.feature.cpconverter.vltpkg.DocViewSerializerContentHandler;
@@ -120,7 +121,10 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
     }
 
     @Override
-    public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception {
+    public void handle(@NotNull String path,
+           @NotNull Archive archive, 
+           @NotNull Entry entry, 
+           @NotNull ContentPackage2FeatureModelConverter converter) throws IOException, ConverterException {
         logger.info("Processing bundle {}...", entry.getName());
 
         Matcher matcher = getPattern().matcher(path);
@@ -136,7 +140,7 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
         }
 
         if (enforceBundlesBelowInstallFolder && !"install".equals(matcher.group("foldername"))) {
-            throw new IllegalStateException("OSGi bundles are only considered if placed below a folder called 'install', but the bundle at '"+ path + "' is placed outside!");
+            throw new ConverterException("OSGi bundles are only considered if placed below a folder called 'install', but the bundle at '"+ path + "' is placed outside!");
         }
 
         
@@ -167,18 +171,19 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
         
         // create a temporary JAR file (extracted from archive)
         Path tmpBundleJar = Files.createTempFile(converter.getTempDirectory().toPath(), "extracted", bundleName + ".jar");
-        try (OutputStream output = Files.newOutputStream(tmpBundleJar);
-             InputStream input = Objects.requireNonNull(archive.openInputStream(entry))) {
-            IOUtils.copy(input, output);
-        }
         try {
+            try (OutputStream output = Files.newOutputStream(tmpBundleJar);
+                InputStream input = Objects.requireNonNull(archive.openInputStream(entry))) {
+                IOUtils.copy(input, output);
+            }
             processBundleInputStream(path, tmpBundleJar, bundleName, runMode, startLevel, converter);
         } finally {
             Files.delete(tmpBundleJar);
         }
     }
 
-    void processBundleInputStream(@NotNull String path, @NotNull Path originalBundleFile, @NotNull String bundleName, @Nullable String runMode, @Nullable Integer startLevel, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception {
+    void processBundleInputStream(@NotNull String path, @NotNull Path originalBundleFile, @NotNull String bundleName, @Nullable String runMode, @Nullable Integer startLevel, @NotNull ContentPackage2FeatureModelConverter converter)
+        throws ConverterException, IOException {
         try (JarFile jarFile = new JarFile(originalBundleFile.toFile())) {
             // first extract bundle metadata from JAR input stream
             ArtifactId id = extractArtifactId(bundleName, jarFile);
@@ -207,7 +212,7 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
         return new Version(originalVersion.getMajor(), originalVersion.getMinor(), originalVersion.getMicro(), originalVersion.getQualifier() + "_" + ContentPackage2FeatureModelConverter.PACKAGE_CLASSIFIER);
     }
 
-    @Nullable InputStream extractSlingInitialContent(@NotNull String path, @NotNull Path bundlePath, @NotNull ArtifactId bundleArtifactId, @NotNull JarFile jarFile, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws Exception {
+    @Nullable InputStream extractSlingInitialContent(@NotNull String path, @NotNull Path bundlePath, @NotNull ArtifactId bundleArtifactId, @NotNull JarFile jarFile, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws IOException, ConverterException {
         if (slingInitialContentPolicy == SlingInitialContentPolicy.KEEP) {
             return null;
         }
@@ -269,7 +274,7 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
      * @return {@code true} in case the given entry was part of the initial content otherwise {@code false}
      * @throws Exception 
      */
-    boolean extractSlingInitialContent(@NotNull JarEntry jarEntry, @NotNull InputStream bundleFileInputStream, @NotNull ArtifactId bundleArtifactId, @NotNull Collection<PathEntry> pathEntries, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull JcrNamespaceRegistry nsRegistry, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception {
+    boolean extractSlingInitialContent(@NotNull JarEntry jarEntry, @NotNull InputStream bundleFileInputStream, @NotNull ArtifactId bundleArtifactId, @NotNull Collection<PathEntry> pathEntries, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull JcrNamespaceRegistry nsRegistry, @NotNull ContentPackage2FeatureModelConverter converter) throws IOException, ConverterException {
         final String entryName = jarEntry.getName();
         // check if current JAR entry is initial content
         Optional<PathEntry> pathEntry = pathEntries.stream().filter(p -> entryName.startsWith(p.getPath())).findFirst();
@@ -321,48 +326,52 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
         return true;
     }
 
-    JcrNamespaceRegistry createNamespaceRegistry(@NotNull Manifest manifest, @NotNull JarFile jarFile, @NotNull Map<String, String> predefinedNamespaceUriByPrefix) throws RepositoryException, IOException, ParseException {
-        JcrNamespaceRegistry registry = new JcrNamespaceRegistry();
-        for (Map.Entry<String, String> entry : predefinedNamespaceUriByPrefix.entrySet()) {
-            registry.registerNamespace(entry.getKey(), entry.getValue());
-        }
+    JcrNamespaceRegistry createNamespaceRegistry(@NotNull Manifest manifest, @NotNull JarFile jarFile, @NotNull Map<String, String> predefinedNamespaceUriByPrefix) throws IOException {
+        try {
+            JcrNamespaceRegistry registry = new JcrNamespaceRegistry();
+            for (Map.Entry<String, String> entry : predefinedNamespaceUriByPrefix.entrySet()) {
+                registry.registerNamespace(entry.getKey(), entry.getValue());
+            }
 
-        // parse Sling-Namespaces header (https://github.com/apache/sling-org-apache-sling-jcr-base/blob/66be360910c265473799635fcac0e23895898913/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java#L192)
-        final String namespacesDefinitionHeader = manifest.getMainAttributes().getValue(NAMESPACES_BUNDLE_HEADER);
-        if (namespacesDefinitionHeader != null) {
-            final StringTokenizer st = new StringTokenizer(namespacesDefinitionHeader, ",");
-
-            while ( st.hasMoreTokens() ) {
-                final String token = st.nextToken().trim();
-                int pos = token.indexOf('=');
-                if ( pos == -1 ) {
-                    logger.warn("createNamespaceRegistry: Bundle {} has an invalid namespace manifest header entry: {}",
-                            manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME), token);
-                } else {
-                    final String prefix = token.substring(0, pos).trim();
-                    final String namespace = token.substring(pos+1).trim();
-                    registry.registerNamespace(prefix, namespace);
+            // parse Sling-Namespaces header (https://github.com/apache/sling-org-apache-sling-jcr-base/blob/66be360910c265473799635fcac0e23895898913/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java#L192)
+            final String namespacesDefinitionHeader = manifest.getMainAttributes().getValue(NAMESPACES_BUNDLE_HEADER);
+            if (namespacesDefinitionHeader != null) {
+                final StringTokenizer st = new StringTokenizer(namespacesDefinitionHeader, ",");
+
+                while ( st.hasMoreTokens() ) {
+                    final String token = st.nextToken().trim();
+                    int pos = token.indexOf('=');
+                    if ( pos == -1 ) {
+                        logger.warn("createNamespaceRegistry: Bundle {} has an invalid namespace manifest header entry: {}",
+                                manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME), token);
+                    } else {
+                        final String prefix = token.substring(0, pos).trim();
+                        final String namespace = token.substring(pos+1).trim();
+                        registry.registerNamespace(prefix, namespace);
+                    }
                 }
             }
-        }
 
-        // parse Sling-Nodetypes header
-        final String typesHeader = manifest.getMainAttributes().getValue(NODETYPES_BUNDLE_HEADER);
-        if (typesHeader != null) {
-            for (ManifestHeader.Entry entry : ManifestHeader.parse(typesHeader).getEntries()) {
-                JarEntry jarEntry = jarFile.getJarEntry(entry.getValue());
-                if (jarEntry == null) {
-                    logger.warn("createNamespaceRegistry: Bundle {} has referenced a non existing node type definition: {}",
-                            manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME), entry.getValue());
-                } else {
-                    try (InputStream inputStream = jarFile.getInputStream(jarEntry);
-                         Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
-                        registry.registerCnd(reader, entry.getValue());
+            // parse Sling-Nodetypes header
+            final String typesHeader = manifest.getMainAttributes().getValue(NODETYPES_BUNDLE_HEADER);
+            if (typesHeader != null) {
+                for (ManifestHeader.Entry entry : ManifestHeader.parse(typesHeader).getEntries()) {
+                    JarEntry jarEntry = jarFile.getJarEntry(entry.getValue());
+                    if (jarEntry == null) {
+                        logger.warn("createNamespaceRegistry: Bundle {} has referenced a non existing node type definition: {}",
+                                manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME), entry.getValue());
+                    } else {
+                        try (InputStream inputStream = jarFile.getInputStream(jarEntry);
+                            Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
+                            registry.registerCnd(reader, entry.getValue());
+                        }
                     }
                 }
             }
+            return registry;
+        } catch ( final RepositoryException | ParseException e) {
+            throw new IOException(e.getMessage(), e);
         }
-        return registry;
     }
 
     /**
@@ -373,7 +382,8 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
      * @param converter
      * @return the VaultPackageAssembler from the cache to use for the given repository path
      */
-    public VaultPackageAssembler initPackageAssemblerForPath(@NotNull ArtifactId bundleArtifactId, @NotNull String repositoryPath, @NotNull PathEntry pathEntry, @NotNull Map<PackageType, VaultPackageAssembler> cache, @NotNull ContentPackage2FeatureModelConverter converter) {
+    public VaultPackageAssembler initPackageAssemblerForPath(@NotNull ArtifactId bundleArtifactId, @NotNull String repositoryPath, @NotNull PathEntry pathEntry, @NotNull Map<PackageType, VaultPackageAssembler> cache, @NotNull ContentPackage2FeatureModelConverter converter) 
+    throws ConverterException {
         PackageType packageType = VaultPackageUtils.detectPackageType(repositoryPath);
         VaultPackageAssembler assembler = cache.get(packageType);
         if (assembler == null) {
@@ -386,7 +396,7 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
                     packageNameSuffix = "-content";
                     break;
                 default:
-                    throw new IllegalStateException("Unexpected package type " + packageType + " detected for path " + repositoryPath);
+                    throw new ConverterException("Unexpected package type " + packageType + " detected for path " + repositoryPath);
             }
             final PackageId packageId = new PackageId(bundleArtifactId.getGroupId(), bundleArtifactId.getArtifactId()+packageNameSuffix, bundleArtifactId.getVersion());
             assembler = VaultPackageAssembler.create(converter.getTempDirectory(), packageId, "Generated out of Sling Initial Content from bundle " + bundleArtifactId + " by cp2fm");
@@ -409,7 +419,7 @@ public class BundleEntryHandler extends AbstractRegexEntryHandler {
         return assembler;
     }
 
-    void finalizePackageAssembly(@NotNull String path, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws Exception {
+    void finalizePackageAssembly(@NotNull String path, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws IOException, ConverterException {
         for (java.util.Map.Entry<PackageType, VaultPackageAssembler> entry : packageAssemblers.entrySet()) {
             File packageFile = entry.getValue().createPackage(false);
             converter.processSubPackage(path + "-" + entry.getKey(), runMode, converter.open(packageFile), true);
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java
index a32e71a..ed6b84e 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandler.java
@@ -16,10 +16,12 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Dictionary;
 
 import org.apache.felix.cm.file.ConfigurationHandler;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 
 public final class ConfigurationEntryHandler extends AbstractConfigurationEntryHandler {
@@ -30,7 +32,7 @@ public final class ConfigurationEntryHandler extends AbstractConfigurationEntryH
 
     @Override
     @SuppressWarnings("unchecked")
-    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception {
+    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws IOException, ConverterException {
         return ConfigurationHandler.read(input);
     }
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ContentPackageEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/ContentPackageEntryHandler.java
index 59b435a..9d408fd 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/ContentPackageEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/ContentPackageEntryHandler.java
@@ -16,8 +16,11 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
+
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -27,9 +30,8 @@ public final class ContentPackageEntryHandler extends AbstractContentPackageHand
     protected void processSubPackage(@NotNull String path, @Nullable String runMode,
                                      @NotNull VaultPackage contentPackage,
                                      @NotNull ContentPackage2FeatureModelConverter converter,
-                                     boolean isEmbeddedPackage) throws Exception {
-        converter.processSubPackage(path, runMode, contentPackage, isEmbeddedPackage);
-        
+                                     boolean isEmbeddedPackage) throws IOException, ConverterException {
+        converter.processSubPackage(path, runMode, contentPackage, isEmbeddedPackage);        
     }
 
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/EntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/EntryHandler.java
index 6c64747..a1fe28f 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/EntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/EntryHandler.java
@@ -16,16 +16,20 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
+
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 
 public interface EntryHandler {
 
     boolean matches(@NotNull String path);
 
-    void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception;
+    void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) 
+    throws IOException, ConverterException;
 
     default EntryHandler withConfig(@NotNull String config) {
         return this;
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandler.java
index d60a3a9..2d5fb46 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
@@ -23,6 +24,7 @@ import java.util.Dictionary;
 import java.util.Hashtable;
 
 import org.apache.felix.cm.json.Configurations;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 
 public final class JsonConfigurationEntryHandler extends AbstractConfigurationEntryHandler {
@@ -32,7 +34,7 @@ public final class JsonConfigurationEntryHandler extends AbstractConfigurationEn
     }
 
     @Override
-    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception {
+    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws IOException, ConverterException {
         final Hashtable<String, Object> props = Configurations.buildReader()
             .withIdentifier(name)
             .build(new InputStreamReader(input, StandardCharsets.UTF_8))
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
index 77f8a41..8570b0c 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
@@ -21,8 +21,10 @@ import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.util.Constants;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.util.Objects;
@@ -53,7 +55,7 @@ public class NodeTypesEntryHandler extends AbstractRegexEntryHandler {
 
     @Override
     public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
+            throws IOException, ConverterException {
         try (Reader cndStatements = new InputStreamReader(Objects.requireNonNull(archive.openInputStream(entry)))) {
             Objects.requireNonNull(converter.getAclManager()).addNodetypeRegistration(IOUtils.toString(cndStatements));
         }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/PropertiesConfigurationEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/PropertiesConfigurationEntryHandler.java
index 95c0160..9bf91ea 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/PropertiesConfigurationEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/PropertiesConfigurationEntryHandler.java
@@ -16,9 +16,11 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.BufferedInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Dictionary;
 import java.util.Enumeration;
@@ -32,7 +34,7 @@ public final class PropertiesConfigurationEntryHandler extends AbstractConfigura
     }
 
     @Override
-    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception {
+    protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws IOException, ConverterException {
         final Properties properties = new Properties();
 
         try (final BufferedInputStream in = new BufferedInputStream(input)) {
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/SlingInitialContentBundleHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/SlingInitialContentBundleHandler.java
index 7884dbb..967f561 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/SlingInitialContentBundleHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/SlingInitialContentBundleHandler.java
@@ -19,11 +19,13 @@ package org.apache.sling.feature.cpconverter.handlers;
 import org.apache.jackrabbit.vault.packaging.PackageType;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Path;
 import java.util.Map;
@@ -38,7 +40,7 @@ public class SlingInitialContentBundleHandler extends BundleEntryHandler {
     }
 
     @Override
-    void processBundleInputStream(@NotNull String path, @NotNull Path originalBundleFile, @NotNull String bundleName, @Nullable String runMode, @Nullable Integer startLevel, @NotNull ContentPackage2FeatureModelConverter converter) throws Exception {
+    void processBundleInputStream(@NotNull String path, @NotNull Path originalBundleFile, @NotNull String bundleName, @Nullable String runMode, @Nullable Integer startLevel, @NotNull ContentPackage2FeatureModelConverter converter) throws IOException, ConverterException {
         try (JarFile jarFile = new JarFile(originalBundleFile.toFile())) {
             // first extract bundle metadata from JAR input stream
             ArtifactId id = extractArtifactId(bundleName, jarFile);
@@ -48,7 +50,7 @@ public class SlingInitialContentBundleHandler extends BundleEntryHandler {
     }
 
     @Override
-    void finalizePackageAssembly(@NotNull String path, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws Exception {
+    void finalizePackageAssembly(@NotNull String path, @NotNull Map<PackageType, VaultPackageAssembler> packageAssemblers, @NotNull ContentPackage2FeatureModelConverter converter, @Nullable String runMode) throws IOException, ConverterException {
         for (java.util.Map.Entry<PackageType, VaultPackageAssembler> entry : packageAssemblers.entrySet()) {
             File packageFile = entry.getValue().createPackage(false);
             handler.processSubPackage(path + "-" + entry.getKey(), runMode, converter.open(packageFile), converter, true);
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/VersionResolverContentPackageEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/VersionResolverContentPackageEntryHandler.java
index c5e9223..51a81b4 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/VersionResolverContentPackageEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/VersionResolverContentPackageEntryHandler.java
@@ -16,11 +16,13 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import java.io.IOException;
 import java.util.Map;
 
 import org.apache.jackrabbit.vault.packaging.PackageId;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.vltpkg.RecollectorVaultPackageScanner;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -42,7 +44,7 @@ public final class VersionResolverContentPackageEntryHandler extends AbstractCon
 
     @Override
     protected void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage contentPackage, @NotNull ContentPackage2FeatureModelConverter converter, boolean isEmbeddedPackage)
-            throws Exception {
+            throws IOException, ConverterException {
 
         boolean addPackage;
         PackageId currentId = contentPackage.getId();
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java b/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
index be9f812..8669311 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/shared/AbstractJcrNodeParser.java
@@ -18,13 +18,16 @@ package org.apache.sling.feature.cpconverter.shared;
 
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
 import java.util.List;
 
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
@@ -44,10 +47,14 @@ public abstract class AbstractJcrNodeParser<O> extends DefaultHandler {
         this.primaryTypes = Arrays.asList(primaryTypes);
     }
 
-    public O parse(InputStream input) throws Exception {
-        SAXParser saxParser = saxParserFactory.newSAXParser();
-        saxParser.parse(input, this);
-        return getParsingResult();
+    public O parse(InputStream input) throws IOException, ConverterException {
+        try {
+            SAXParser saxParser = saxParserFactory.newSAXParser();
+            saxParser.parse(input, this);
+            return getParsingResult();    
+        } catch ( final ParserConfigurationException | SAXException e) {
+            throw new IOException(e.getMessage(), e);
+        }
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/BaseVaultPackageScanner.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/BaseVaultPackageScanner.java
index 1df8c2b..1e100a3 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/BaseVaultPackageScanner.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/BaseVaultPackageScanner.java
@@ -20,6 +20,7 @@ import static java.util.Objects.requireNonNull;
 import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_CND_PATTERN;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.regex.Pattern;
 
 import org.apache.jackrabbit.vault.fs.io.Archive;
@@ -29,6 +30,7 @@ import org.apache.jackrabbit.vault.packaging.PackageManager;
 import org.apache.jackrabbit.vault.packaging.PackageProperties;
 import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.jackrabbit.vault.packaging.impl.PackageManagerImpl;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -51,7 +53,7 @@ public abstract class BaseVaultPackageScanner {
         this.strictValidation = strictValidation;
     }
 
-    public @NotNull VaultPackage open(@NotNull File vaultPackage) throws Exception {
+    public @NotNull VaultPackage open(@NotNull File vaultPackage) throws IOException, ConverterException {
         requireNonNull(vaultPackage, "Impossible to process a null vault package");
         return packageManager.open(vaultPackage, strictValidation);
     }
@@ -70,7 +72,7 @@ public abstract class BaseVaultPackageScanner {
         }
     }
 
-    public final void traverse(@NotNull VaultPackage vaultPackage) throws Exception {
+    public final void traverse(@NotNull VaultPackage vaultPackage) throws IOException, ConverterException {
         requireNonNull(vaultPackage, "Impossible to process a null vault package");
 
         PackageProperties properties = vaultPackage.getProperties();
@@ -92,7 +94,7 @@ public abstract class BaseVaultPackageScanner {
         }
     }
 
-    private void traverse(@Nullable String path, @NotNull Archive archive, @NotNull Entry entry) throws Exception {
+    private void traverse(@Nullable String path, @NotNull Archive archive, @NotNull Entry entry) throws IOException, ConverterException {
         String entryPath = newPath(path, entry.getName());
 
         if (entry.isDirectory()) {
@@ -124,7 +126,7 @@ public abstract class BaseVaultPackageScanner {
         // do nothing by default
     }
 
-    protected void onFile(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry) throws Exception {
+    protected void onFile(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry) throws IOException, ConverterException {
         // do nothing by default
     }
 
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
index 2338842..fddd6ef 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/RecollectorVaultPackageScanner.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.feature.cpconverter.vltpkg;
 
+import java.io.IOException;
 import java.util.Map;
 
 import org.apache.jackrabbit.vault.fs.io.Archive;
@@ -23,6 +24,7 @@ import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.packaging.PackageId;
 import org.apache.jackrabbit.vault.packaging.PackageManager;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.handlers.EntryHandler;
 import org.apache.sling.feature.cpconverter.handlers.GroupEntryHandler;
 import org.apache.sling.feature.cpconverter.handlers.SlingInitialContentBundleHandler;
@@ -53,7 +55,7 @@ public final class RecollectorVaultPackageScanner extends BaseVaultPackageScanne
     }
 
     @Override
-    protected void onFile(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry) throws Exception {
+    protected void onFile(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry) throws IOException, ConverterException {
         for (EntryHandler handler : handlers) {
             if (handler.matches(path)) {
                 handler.handle(path, archive, entry, converter);
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
index ab1b3a3..c9a1d64 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/VaultPackageAssembler.java
@@ -36,6 +36,7 @@ import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.jackrabbit.vault.util.Constants;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.handlers.EntryHandler;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -191,7 +192,7 @@ public class VaultPackageAssembler implements EntryHandler {
 
     @Override
     public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
-            throws Exception {
+            throws IOException, ConverterException {
         if (removeInstallHooks && path.startsWith("/" + Constants.META_DIR + "/" + Constants.HOOKS_DIR)) {
             log.info("Skipping install hook {} from original package", path);
         } else {
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/Util.java b/src/test/java/org/apache/sling/feature/cpconverter/Util.java
index 43db798..f1e4c3c 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/Util.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/Util.java
@@ -29,11 +29,12 @@ public class Util {
     public static String normalize(String repoinit) throws RepoInitParsingException {
         RepoInitParser parser = new RepoInitParserService();
         List<Operation> operations = parser.parse(new StringReader(repoinit));
-        Formatter formatter = new Formatter();
-        for (Operation op : operations) {
-            formatter.format("%s", op.asRepoInitString());
+        try ( Formatter formatter = new Formatter()) {
+            for (Operation op : operations) {
+                formatter.format("%s", op.asRepoInitString());
+            }
+            return formatter.out().toString();    
         }
-        return formatter.out().toString();
     }
 
     public static String normalizeUnchecked(String repoinit) {
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandlerGAVTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandlerGAVTest.java
index f83b353..a0414ca 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandlerGAVTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/BundleEntryHandlerGAVTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.when;
 
 import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
@@ -53,6 +54,6 @@ public class BundleEntryHandlerGAVTest extends AbstractBundleEntryHandlerTest {
     public void testBundleBelowConfigFolderWithEnforcement() throws Exception {
         handler.setEnforceBundlesBelowInstallFolder(true);
         when(entry.getName()).thenReturn("mybundle.jar");
-        assertThrows(IllegalStateException.class, () -> { handler.handle("/jcr_root/apps/myapp/config/mybundle.jar", null, entry, null); });
+        assertThrows(ConverterException.class, () -> { handler.handle("/jcr_root/apps/myapp/config/mybundle.jar", null, entry, null); });
     }
 }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigEntryHandlerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigEntryHandlerTest.java
index f323adf..004b15f 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigEntryHandlerTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigEntryHandlerTest.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringReader;
 import java.io.StringWriter;
@@ -42,6 +43,7 @@ import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.ConverterException;
 import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
@@ -112,7 +114,7 @@ public class ConfigEntryHandlerTest {
 
         AbstractConfigurationEntryHandler handler = new AbstractConfigurationEntryHandler("cfg") {
             @Override
-            protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws Exception {
+            protected @NotNull Dictionary<String, Object> parseConfiguration(@NotNull String name, @NotNull InputStream input) throws IOException {
                 return new Hashtable(){{put("foo", "bar");}};
             }
         };
@@ -129,7 +131,7 @@ public class ConfigEntryHandlerTest {
         Archive archive = Mockito.mock(Archive.class);
         Entry entry = Mockito.mock(Entry.class);
         Mockito.when(archive.openInputStream(entry)).thenReturn(new ByteArrayInputStream(new byte[0]));
-        assertThrows(IllegalStateException.class, () -> {
+        assertThrows(ConverterException.class, () -> {
             handler.handle("/jcr_root/apps/myapp/install/myconfig.config", archive, entry, Mockito.mock(ContentPackage2FeatureModelConverter.class));
         });
     }