question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support catch NoClassDefFoundError exception When use ClassLoaderWrapper load Class

See original GitHub issue

MyBatis version

3.5.3

Database vendor and version

use MySQL 5.6.16 SpringBoot 2.3.2.RELEASE

Test case or example project

When MyBatis integrates Spring Boot, the Mapper XML uses OGNL expressions to refer to nested enumeration constant classes, causing a NoClassDefFoundError exception

The below constains OrgEnum, TestController class, User entity class, UserMapper interface and user.xml mapper

@Getter
@RequiredArgsConstructor
public enum OrgEnum {

    //org info
    AB("000001", "ABorg"),
    CD("000002", "CDorg");

    private final String code;
    private final String name;

    //constants

    public static final String AB_ORG_CODE = AB.getCode();
    public static final String CD_ORG_CODE = CD.getCode();

    public static final String D1_DEPARTMENT_CODE = OrgEnum.DepartmentEnum.D1_DEPARTMENT.getCode();

    /**
     * 保司信息
     */
    @Getter
    @RequiredArgsConstructor
    public enum DepartmentEnum {

        // department  info
        D1_DEPARTMENT(OrgEnum.AB, "D001", "D001Info..."),
        D2_DEPARTMENT(OrgEnum.AB, "D002", "D002Info..."),
        D3_DEPARTMENT(OrgEnum.CD, "D003", "D003Info..."),
        ;

        private final OrgEnum org;
        private final String code;
        private final String name;
    }
}
@RestController
@RequestMapping("test")
@RequiredArgsConstructor
public class TestController {

    private final UserMapper userMapper;

    @GetMapping
    public User get(Long id) {
        Objects.requireNonNull(id);
        return userMapper.getOne(id);
    }

}
@Data
public class User {

    private String orgCode;
    private String name;
}
public interface UserMapper {

    User getOne(Long id);
}

The below is sql use ognl expression in user.xml

 <select id="getOne" resultMap="com.example.demo.t.User">
    SELECT
        '${@com.example.demo.t.OrgEnum@AB_ORG_CODE}' AS orgCode,
        name
    FROM
        user
    WHERE
        id = #{id}
</select>

When client request TestController#get method,The Mybatis throw java.lang.NoClassDefFoundError exception ,the below is detial info

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class com.example.demo.t.OrgEnum
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.example.demo.t.OrgEnum
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:186)
	at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89)
	at org.apache.ibatis.io.Resources.classForName(Resources.java:261)
	at org.apache.ibatis.scripting.xmltags.OgnlClassResolver.toClassForName(OgnlClassResolver.java:34)
	at org.apache.ibatis.ognl.DefaultClassResolver.classForName(DefaultClassResolver.java:58)
	at org.apache.ibatis.ognl.OgnlRuntime.classForName(OgnlRuntime.java:1167)
	at org.apache.ibatis.ognl.OgnlRuntime.getStaticField(OgnlRuntime.java:2059)
	at org.apache.ibatis.ognl.ASTStaticField.getValueBody(ASTStaticField.java:68)
	at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
	at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
	at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:493)
	at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:457)
	at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46)
	at org.apache.ibatis.scripting.xmltags.TextSqlNode$BindingTokenParser.handleToken(TextSqlNode.java:77)
	at org.apache.ibatis.parsing.GenericTokenParser.parse(GenericTokenParser.java:77)
	at org.apache.ibatis.scripting.xmltags.TextSqlNode.apply(TextSqlNode.java:51)
	at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
	at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:39)
	at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:297)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426)
	at com.sun.proxy.$Proxy123.selectList(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:223)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:93)
	at com.sun.proxy.$Proxy130.selectGift2Short(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)

when I debug it ,I find the method org.apache.ibatis.io.ClassLoaderWrapper#classForName(java.lang.String, java.lang.ClassLoader[]) second args contains three ClassLoaders,and first ClassLoader is org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader,anoter ClassLoader is AppClassLoader, while the second args ClassLoader[] is from the method org.apache.ibatis.io.ClassLoaderWrapper#getClassLoaders, and have a Thread.currentThread().getContextClassLoader(),that is TomcatEmbeddedWebappClassLoader,of this time, when custom ClassLoader not load Class and throw NoClassDefFoundError, the Mybatis framework should catch it, rather that just catch ClassNotFoundException The method ClassLoaderWrapper#classForName have below code

for (ClassLoader cl : classLoader) {

      if (null != cl) {

        try {

          Class<?> c = Class.forName(name, true, cl);

          if (null != c) {
            return c;
          }

        } catch (ClassNotFoundException e) {
          // we'll ignore this until all classloaders fail to locate the class
        }

      }

    }

The method org.apache.ibatis.io.ClassLoaderWrapper#getClassLoaders code is

return new ClassLoader[]{
        classLoader,
        defaultClassLoader,
        Thread.currentThread().getContextClassLoader(),
        getClass().getClassLoader(),
        systemClassLoader};
  }

Steps to reproduce

use http client request TestController#get method

Expected result

select orgCode and set User#orgCode

Actual result

throw java.lang.NoClassDefFoundError

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
FuriousPws002commented, Jan 24, 2021

It’s OK,Thanks for your answers

1reaction
wuwen5commented, Jan 23, 2021
public static final String D1_DEPARTMENT_CODE = OrgEnum.DepartmentEnum.D1_DEPARTMENT.getCode();

There is a circular dependency,When I try to remove this line , it’s ok.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I solve "java.lang.NoClassDefFoundError"?
The NoClassDefFoundError indicates that the classloader (in this case java.net.URLClassLoader ), which is responsible for dynamically loading classes, ...
Read more >
How to Resolve the NoClassDefFoundError in Java - Rollbar
NoClassDefFoundError is a Java error that occurs when the JVM is unable to find a class at runtime which was available at compile-time....
Read more >
3 ways to solve java.lang.NoClassDefFoundError in Java J2EE
ClassNotFoundException comes when JVM tries to load a class at runtime ... the J2EE environment then you can get NoClassDefFoundError even if the...
Read more >
ClassNotFoundException vs NoClassDefFoundError - Baeldung
Both ClassNotFoundException and NoClassDefFoundError occur when the JVM can not find a requested class on the classpath.
Read more >
ClassNotFoundException Vs. NoClassDefFoundError In Java
An application itself throws the ClassNotFoundException. It is thrown by the methods that explicitly loads the class using its name like Class.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found