Hi all,

I'm currently facing a problem with the CDIScanner in TomEE. I noticed this
old JIRA https://issues.apache.org/jira/browse/TOMEE-1640

To avoid potential NCDF errors in CDI Extensions using reflection, we
introduced an eager check for NCDF errors while registering beans. But by
default the error is swallowed and the bean is not registered. So if you
have a bean with a dependency to a bean where the eager check failed, then
the exception is reported at the wrong place

Here is an example.

public class BeanA {
  private final MyDep dep = new MyDep();
}

MyDep comes from a library not available in the application or in TomEE.
When scanning BeanA, our CDIScanner will load the class as follow

private Class load(final String className, final ClassLoader classLoader) {
    try {
        final Class<?> loadClass = classLoader.loadClass(className);
        tryToMakeItFail(loadClass);
        return loadClass;
    } catch (final ClassNotFoundException e) {
        return null;
    } catch (final NoClassDefFoundError e) {
        if (logDebug) {
            Logger.getInstance(LogCategory.OPENEJB_CDI,
CdiScanner.class).warning(className + " -> " + e);
        }
        return null;
    }
}

private void tryToMakeItFail(final Class<?> loadClass) { // we try to
avoid later NoClassDefFoundError
    loadClass.getDeclaredFields();
    loadClass.getDeclaredMethods();
}


This will trigger a NCDF because MyDep isn't available, and even though the
bean class is not used anymore or part of a feature under development and
not fully available.

The spec says

> Deployment problems are detected by the container at initialization time.
> If a deployment problem exists in a deployment, initialization will be
> aborted by the container.
>
> The container is permitted to define a non-portable mode, for use at
> development time, in which some definition errors and deployment problems
> do not cause application initialization to abort.
>
>
To me, tryToMakeItFail must be called only if the logDebug flag is true. If
not, then we should not eagerly try to load dependencies.

Also because now let's assume there is a

public class BeanB {
  @Inject private BeanClassA bean;
}

The app will fail at deploy time because of an unsatisfied dependency. It
won't be able to inject BeanA into BeanB, because BeanA dependencies failed
to load and the bean is discarded without any logs.

That being said, I'm not sure what the default should be.


   - Should we "just" do what's required in the spec and not eagerly try to
   load dependencies and let the extension to "maybe" fail later
   - Eagerly test but then log without having to set up a flag
   - Eagerly test and fail deployment which might generate failures for
   beans not used in the application


We are halfway between 1 and 2.

Hopefully it's clear.
What do you guys think?

I'd go for 2 but with a slightly more noticable error.

--
Jean-Louis Monteiro
http://twitter.com/jlouismonteiro
http://www.tomitribe.com

Reply via email to