diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index c16fff7c2b6..93b703e8516 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -218,6 +218,10 @@ Other (https://scan.coverity.com/projects/5620 CID 120656) (Christine Poerschke, Coverity Scan (via Rishabh Patel)) +* LUCENE-6961: Improve Exception handling in AnalysisFactories / + AnalysisSPILoader: Don't wrap exceptions occuring in factory's + ctor inside InvocationTargetException. (Uwe Schindler) + ======================= Lucene 5.4.0 ======================= New Features diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java index b41e784de73..c7dd9673207 100644 --- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/util/AnalysisSPILoader.java @@ -17,6 +17,7 @@ package org.apache.lucene.analysis.util; * limitations under the License. */ +import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collections; import java.util.Locale; @@ -111,12 +112,7 @@ final class AnalysisSPILoader { public S newInstance(String name, Map args) { final Class service = lookupClass(name); - try { - return service.getConstructor(Map.class).newInstance(args); - } catch (Exception e) { - throw new IllegalArgumentException("SPI class of type "+clazz.getName()+" with name '"+name+"' cannot be instantiated. " + - "This is likely due to a misconfiguration of the java class '" + service.getName() + "': ", e); - } + return newFactoryInstance(service, args); } public Class lookupClass(String name) { @@ -133,4 +129,21 @@ final class AnalysisSPILoader { public Set availableServices() { return services.keySet(); } + + public static T newFactoryInstance(Class clazz, Map args) { + try { + return clazz.getConstructor(Map.class).newInstance(args); + } catch (InvocationTargetException ite) { + final Throwable cause = ite.getCause(); + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + if (cause instanceof Error) { + throw (Error) cause; + } + throw new RuntimeException(cause); + } catch (ReflectiveOperationException e) { + throw new UnsupportedOperationException("Factory "+clazz.getName()+" cannot be instantiated. This is likely due to missing Map constructor.", e); + } + } } diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestAllAnalyzersHaveFactories.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestAllAnalyzersHaveFactories.java index 279e45f9889..559db2da4e6 100644 --- a/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestAllAnalyzersHaveFactories.java +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestAllAnalyzersHaveFactories.java @@ -150,10 +150,6 @@ public class TestAllAnalyzersHaveFactories extends LuceneTestCase { } assertSame(c, instance.create().getClass()); } catch (IllegalArgumentException e) { - if (e.getCause() instanceof NoSuchMethodException) { - // there is no corresponding ctor available - throw e; - } // TODO: For now pass because some factories have not yet a default config that always works } } else if (TokenFilter.class.isAssignableFrom(c)) { @@ -174,10 +170,6 @@ public class TestAllAnalyzersHaveFactories extends LuceneTestCase { assertSame(c, createdClazz); } } catch (IllegalArgumentException e) { - if (e.getCause() instanceof NoSuchMethodException) { - // there is no corresponding ctor available - throw e; - } // TODO: For now pass because some factories have not yet a default config that always works } } else if (CharFilter.class.isAssignableFrom(c)) { @@ -198,10 +190,6 @@ public class TestAllAnalyzersHaveFactories extends LuceneTestCase { assertSame(c, createdClazz); } } catch (IllegalArgumentException e) { - if (e.getCause() instanceof NoSuchMethodException) { - // there is no corresponding ctor available - throw e; - } // TODO: For now pass because some factories have not yet a default config that always works } }