emacarron / mybatis

Automatically exported from code.google.com/p/mybatis
0 stars 0 forks source link

MyBatis loading fails on Glassfish 3.0.1 #146

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What version of the MyBatis are you using?
MyBatis 3.0.2

Please describe the problem.  Unit tests are best!
When trying to use MyBatis in glassfish. MyBatis loading fails with:

with java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

What is the expected output? What do you see instead?
MyBatis loaded.

Please provide any additional information below.

It seems a glassfish problem. Glassfish comes with slf4j so MyBatis detects it 
and tries to use it. Mybatis executes this two sentences 

Resources.classForName("org.slf4j.LoggerFactory");
Logger log = org.slf4j.LoggerFactory.LoggerFactory.getLogger(<parameter.class>);

Surprisingly the first one works but the second fails with 
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory. So I would say that 
slf4j logging system seems to be unusable. Maybe some dependency is missing in 
glassfish. 

To solve this I can think in three possibilities:
1- change the order so that MyBatis tries first another log system
2- change mybatis to to try loggers calling getLogger (not just loading the 
class)
3- do not propagate the exeption if getLog fails.

Option 2:
  private static void setImplementation(String testClassName, String implClassName) {
    try {
      Resources.classForName(testClassName);
      Class implClass = Resources.classForName(implClassName);
      logConstructor = implClass.getConstructor(new Class[]{Class.class});
      // probe log to ensure it really works
      getLog(LogFactory.class).debug("Logger initiated over " + testClassName);
    } catch (Throwable t) {
      throw new LogException("Error setting Log implementation.  Cause: " + t, t);
    }
  }

Option3:

  public static Log getLog(Class aClass) {
    try {
      return (Log) logConstructor.newInstance(new Object[]{aClass});
    } catch (Throwable t) {
      // ignored
    }
  }

Original issue reported on code.google.com by eduardo.macarron on 17 Oct 2010 at 6:20

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
This is the change I am using and works fine

  static {
    tryImplementation(new Runnable() {
      public void run() {
        useCommonsLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useLog4JLogging();
      }
    });
    tryImplementation(new Runnable() {
        public void run() {
          useSlf4jLogging();
        }
      });
    tryImplementation(new Runnable() {
      public void run() {
        useJdkLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useNoLogging();
      }
    });
  }

Original comment by eduardo.macarron on 30 Oct 2010 at 6:24

GoogleCodeExporter commented 9 years ago
Glassfish loads slf4j and mybatis with these classloaders:
INFO: sun.misc.Launcher$AppClassLoader@fabe9
INFO: WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)

Seems that MyBatis classes cannot see slf4j so Resources can load slf4j but it 
later fails when trying to use it.

Fixed adding a probe for each logging adapter instead of just loading the 
underliying 3rd party logging class.

See r3463 

Original comment by eduardo.macarron on 30 Dec 2010 at 12:17