Search code examples
javaspring-bootjvmbyte-buddyjavaagents

Byte Buddy Not Loading Classes and Throwing Class Not Found


Am trying to build custom agent for springboot application. This how my agent premain looks

                .with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
                .ignore(ElementMatchers.nameStartsWith("org.springframework.boot"))
                .type((ElementMatchers.any()))
                .transform((builder, typeDescription, classLoader, module) -> builder
                        .method(ElementMatchers.any())
                        .intercept(Advice.to(MyInterceptor.class))
                ).installOn(instrumentation);

I am trying to not instrument methods inside the boot loader classes

When am trying to attach the agent to my spring boot application on startup this is the error am getting

Exception in thread "main" java.lang.NoClassDefFoundError: sun/reflect/GeneratedMethodAccessor14
    at sun.reflect.GeneratedMethodAccessor14.<clinit>(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:403)
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
    at sun.reflect.MethodAccessorGenerator.generateMethod(MethodAccessorGenerator.java:75)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:53)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.misc.CompoundEnumeration.<clinit>(CompoundEnumeration.java)
    at java.lang.ClassLoader.getResources(ClassLoader.java:1144)
    at java.lang.ClassLoader.getResources(ClassLoader.java:1138)
    at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:348)
    at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
    at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
    at java.time.zone.ZoneRulesProvider.<clinit>(ZoneRulesProvider.java:165)
    at java.time.ZoneRegion.ofId(ZoneRegion.java:120)
    at java.time.ZoneId.of(ZoneId.java:411)
    at java.time.ZoneId.of(ZoneId.java:359)
    at java.time.ZoneId.of(ZoneId.java:315)
    at java.util.TimeZone.toZoneId(TimeZone.java:556)
    at sun.util.calendar.ZoneInfo.toZoneId(ZoneInfo.java)
    at java.time.ZoneId.systemDefault(ZoneId.java:274)
    at org.springframework.boot.loader.jar.CentralDirectoryFileHeader.decodeMsDosFormatDateTime(CentralDirectoryFileHeader.java:130)
    at org.springframework.boot.loader.jar.CentralDirectoryFileHeader.getTime(CentralDirectoryFileHeader.java:116)
    at org.springframework.boot.loader.jar.JarEntry.<init>(JarEntry.java:58)
    at org.springframework.boot.loader.jar.JarFileEntries.getEntry(JarFileEntries.java:316)
    at org.springframework.boot.loader.jar.JarFileEntries.access$400(JarFileEntries.java:48)
    at org.springframework.boot.loader.jar.JarFileEntries$EntryIterator.next(JarFileEntries.java:366)
    at org.springframework.boot.loader.jar.JarFileEntries$EntryIterator.next(JarFileEntries.java:350)
    at org.springframework.boot.loader.jar.JarFile$2.nextElement(JarFile.java:201)
    at org.springframework.boot.loader.jar.JarFile$2.nextElement(JarFile.java:192)
    at org.springframework.boot.loader.archive.JarFileArchive$EntryIterator.next(JarFileArchive.java:184)
    at org.springframework.boot.loader.archive.JarFileArchive$EntryIterator.next(JarFileArchive.java:169)
    at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:85)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.getClassPathArchives(ExecutableArchiveLauncher.java:69)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
Caused by: java.lang.ClassNotFoundException: sun.reflect.GeneratedMethodAccessor14
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 43 more

Am I doing something wrong here on how to ignore particular matchers? `


Solution

  • The eager self-injecting strategy can load types prematurely and you should not use it. If you register an AgentBuilder.Listener, you will probably see the error causing this loading problem. I think you want to use advice as a decorator, not as an implementation:

    (builder, typeDescription, classLoader, module) -> builder.visit(Advice
        .to(MyInterceptor.class)
        .on(isMethod())
    

    This way, the method implementations are decorated rather then replaced. Also, remove the injection strategy, there is nothing to inject here.