jeudi 18 février 2021

Mocking a class whose static initializer threw ExceptionInInitializerError

I have a scenario where I need to load classes from unknown sources and instantiate them for mocking - I don't need the code to run, but methods and properties must be in the resulting instance. I also need the class's name to remain unchanged, so its instance can be assigned to fields from that type of other already loaded classes. Sometimes a class instantiation fails due to an ExceptionInInitializerError, leaving the class in an invalid state which is impossible to recover. I do not know which class will fail beforehand.

Consider this:

class A {
    static {
        // Throws exception, resulting in 'A' changing to an error state
    }
}
    
class B {
    // In case 'A' could not be instantiated properly, I wish to mock
    // it so it can be assigned to this field
    private A someField;
}

The following is what I came up with:

  1. Create a subclass of the failing class using ByteBuddy - fails with NoClassDefFoundError, probably because the superclass is in an error state.
  2. Modify the class's static initializer and wrap it in try-catch statements while it is loaded using a ByteBuddy's agent - this seems rather complicated to accomplish in a portable manner.
  3. Load a class in a separate temporary class loader and identify the initialization failure; if an ExceptionInInitializerError has been thrown, redefine that class and remove its static initializer. This also appears very complex to achieve and results in various linkage and circularity errors.

Am I missing something? Is there a simpler way to achieve what I'm looking for?





Aucun commentaire:

Enregistrer un commentaire