Skip to content

Core: Handle ExceptionInInitializerError & NoClassDefFoundError invoke-time failures in DynMethods callers#16611

Open
nastra wants to merge 1 commit into
apache:mainfrom
nastra:dyn-handling
Open

Core: Handle ExceptionInInitializerError & NoClassDefFoundError invoke-time failures in DynMethods callers#16611
nastra wants to merge 1 commit into
apache:mainfrom
nastra:dyn-handling

Conversation

@nastra

@nastra nastra commented May 29, 2026

Copy link
Copy Markdown
Contributor

DynMethods use Class.forName which can throw NoClassDefFoundError or
ExceptionInInitializerError when a method is found but its body
references a missing transitive dependency or triggers a failing static
initializer. This causes FormatModelRegistry.<clinit> and InternalData.<clinit> to fail
permanently when optional modules like iceberg-orc or iceberg-parquet are absent (#16720).
This widens the catch blocks in FormatModelRegistry.registerSupportedFormats()
and InternalData.registerSupportedFormats() to handle these invoke-time
failures the same way as NoSuchMethodException

The initial version was created by Claude and tests were manually adjusted

@nastra nastra changed the title Common: Handle ExceptionInInitializerError & NoClassDefFoundError during optional Dyn* class loading Common, Core: Handle ExceptionInInitializerError & NoClassDefFoundError during optional Dyn* class loading May 29, 2026
Comment thread common/src/main/java/org/apache/iceberg/common/DynClasses.java
Comment thread common/src/main/java/org/apache/iceberg/common/DynConstructors.java
Comment thread core/src/main/java/org/apache/iceberg/formats/FormatModelRegistry.java Outdated
Class<?> targetClass = classForName(className);
impl(targetClass, types);
} catch (NoClassDefFoundError | ClassNotFoundException e) {
} catch (NoClassDefFoundError | ClassNotFoundException | ExceptionInInitializerError e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove changes to this class. I don't think that this is necessary to fix the bug and this is an over-broad change to the contract of our reflection classes that are used in a lot of places.

@rdblue rdblue left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be much more narrow. We can talk about changes to the reflection classes separately.

@nastra nastra force-pushed the dyn-handling branch 2 times, most recently from 2ffb413 to bcb4854 Compare June 9, 2026 09:42
@nastra nastra changed the title Common, Core: Handle ExceptionInInitializerError & NoClassDefFoundError during optional Dyn* class loading Core: Handle ExceptionInInitializerError & NoClassDefFoundError invoke-time failures in DynMethods callers Jun 9, 2026
}

@Test
void registerDoesNotFailWhenClassThrowsNoClassDefFoundOnInvoke() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are a bit awkward, and hard to understand what they are actually test. Shall we create a package private classesToRegister() method and override it in the tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reproducing the original issue in a unit test without mocking out a bunch of things is a bit difficult because we'd have to simulate that parquet/orc isn't on the classpath. Also I didn't want to provide a fix without having a test that at least shows how the issue can happen in practice. So I figured we might want to just have a try/catch block that essentially does what's being handled in the affected classes.

I'm open to other ideas though. Using a package-private classesToRegister() might work for FormatModelRegistry but not for InternalData.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we create a 'register(String)' method both in InternalData and FormatModelRegistry?
We can call this from the prouction code and from the test too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants