Why "Failed to define class" WARN from server startup?

Liquibase internally scans your classpath using your classloader to find classes that may be Liquibase extensions. Part of that scanning is hitting a few classes that are bundled with the liquibase jar but are not part of the normal liquibase update process.

In particular, it is checking code that displays the database and liquibase state that can be helpful in demos and troubleshooting and other code that can be used for testing extensions.

These non-standard use classes reference additional dependencies such as jetty and junit and which are normally not available in production environments and so Liquibase expects some ClassNotFoundExceptions and DEBUG-level logs them, moves on, and updates correctly as you are seeing.

In your case, it appears that the JBoss classloader has an additional feature to log at WARN level any ClassNotFoundExceptions it runs into throwing it up the chain to the point that Liquibase ignores it.

A future release of Liquibase will better split between the "tools" codebase and the "standard" codebase, but for now your options would be:

  • Include the missing dependencies in your classpath (jetty and junit based in your stacktrace)
  • Create enough of a stub class named the same as the referenced jetty and junit classes in order to make the class loader happy.
  • Set the log level for "org.jboss.modules" to ERROR in order to not log WARN-level logs

I have used this class, which very probably will not work on jetty, but on all other servers (tomcat, jboss/wildfly, weblogic, websphere, glassfish, tomee, ...) I've tested it on tomcat and wildfly.

package org.eclipse.jetty.server.handler;

/**
 * Workaround for this issues in liquibase.
 * http://stackoverflow.com/questions/26530677/why-failed-to-define-class-warn-from-server-startup.
 * https://liquibase.jira.com/browse/CORE-2024.
 *
 * @author cilap
 *
 */
public class AbstractHandler {

   /**
    * Trace to logfile the workaround.
    */
   public AbstractHandler() {
      System.err.println("Workaround for http://stackoverflow.com/questions    /26530677/why-failed-to-define-class-warn-from-server-startup and "
            + "https://liquibase.jira.com/browse/CORE-2024");
      System.err.println("please remove this from the repository as soon as the bug is fixed on liquibase.");
   }
}

This is not nice but it works.

Edit1:

The Classloader is searching for the Class org.eclipse.jetty.server.handler.AbstractHandler Since we are not on the Jetty, the class cannot be found by the classloader.

One option would be to add the jetty jar file into the tomcat or the wildfly, BUT this will very probably cause issues on tomcat/wildfly, since they implement also expected interfaces and classes which both, Jetty and Wildfly/tomcat provide. To avoid this - until it is fixed by Liquibase - you have to provide the Classloader a dummy implementation of AbstractHandler. So the classloader is happy and finds the AbstractHandler and the WARN message is gone.

As said this is not nice but is a workaround to get rid of the odd messages in the logfile and console. If we are lucky, liquibase may incorporate a fix for this minor bug in 3.4 or maybe in 4.0.