Why Adding Fastjson to a SpringBoot Agent Breaks Class Loading

A Java developer added fastjson to a SkyWalking agent for JSON conversion, causing class‑loading conflicts in a SpringBoot 2 application; the article analyzes the root cause, demonstrates debugging steps, explains the parent‑delegation mechanism, and presents solutions using Maven shade relocation or switching to Gson, with practical lessons for avoiding similar issues.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Why Adding Fastjson to a SpringBoot Agent Breaks Class Loading

Background

Recently added a feature to report exceptions in an agent. To convert objects to JSON in HTTP requests, a fastjson dependency was added, which caused various problems.

Environment:

JDK 1.8

SpringBoot 2.0.0.RELEASE

skywalking agent 8.14.0

Problem Appearance

2.1 Initial Diagnosis

Colleagues reported that the application starts locally but fails to start in the test environment with the agent attached, showing an error.

First, verify whether the issue is a dependency conflict. The class GenericHttpMessageConverter belongs to spring‑web, which is present in the test package, so this is not the cause.

Then suspect the agent. Disabling the agent allows the application to start, confirming the agent is the source of the problem.

2.2 Further Investigation

Downloaded the failing package, attached the agent locally, and reproduced the error, enabling debugging.

When starting the application with IDEA (agent attached) there is no problem; the reason is explained later.

Set a conditional breakpoint at java.net.URLClassLoader#findClass for GenericHttpMessageConverter. The breakpoint is hit shortly after startup.

IDEA shows three calls to findClass and the classes loaded each time:

The first trigger originates from the third‑party class WebAutoConfig.

BootMessageConverter (third‑party) → FastJsonHttpMessageConverter (fastjson) → GenericHttpMessageConverter (spring‑web)

Code that triggers class loading:

@Configuration
public class WebAutoConfig implements WebMvcConfigurer {
    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters httpMessageConverter() {
        BootMessageConverter converter = new BootMessageConverter(); // triggers class loading
        ...
    }
}
public class BootMessageConverter extends FastJsonHttpMessageConverter { ... }
public class FastJsonHttpMessageConverter extends AbstractHttpMessageConverter<Object>
        implements GenericHttpMessageConverter<Object> { ... }

The chain shows that BootMessageConverter loads FastJsonHttpMessageConverter, which in turn loads GenericHttpMessageConverter. Because the agent supplies its own fastjson classes, the AppClassLoader loads them first, but it cannot find GenericHttpMessageConverter (which resides in the application’s spring‑web jar loaded by LaunchedURLClassLoader). The parent‑delegation mechanism prevents the LaunchedURLClassLoader from loading the missing class, resulting in a ClassNotFoundException.

Running the application directly from IDEA uses the application’s main class, not SpringBoot’s JarLauncher, so all classes are loaded by AppClassLoader and the conflict does not appear.

Solution 1: Maven Shade Plugin

To prevent the agent’s fastjson classes from being intercepted by AppClassLoader, rename the fastjson package in the agent using maven‑shade‑plugin relocation.

Sample plugin configuration (excerpt):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>shade</goal></goals>
            <configuration>
                <relocations>
                    <relocation>
                        <pattern>com.alibaba.fastjson</pattern>
                        <shadedPattern>shade.com.alibaba.fastjson</shadedPattern>
                    </relocation>
                </relocations>
                ...
            </configuration>
        </execution>
    </executions>
</plugin>

After shading, the fastjson classes in the agent are prefixed with shade., so the application’s fastjson classes are loaded independently and the conflict disappears.

Reproducing the Issue

Later another application failed with a similar ClassNotFoundException. The root cause was Jersey’s SPI mechanism loading javax.ws.rs.ext.MessageBodyReader implementations from the agent’s shaded fastjson JAR, which referenced classes only present in the application (jsr311‑api). This again caused a missing‑class error.

Decision: Drop Fastjson

Instead of shading, replace fastjson with a lightweight library that has no transitive dependencies or SPI files. Google’s gson meets this requirement.

Gson’s pom contains only JUnit as a test dependency and no META-INF/services entries, eliminating the class‑loading conflicts.

Conclusion

Prefer JDK‑built‑in classes for agent functionality to minimize third‑party dependencies.

If third‑party libraries are required, use maven‑shade‑plugin to relocate packages and isolate them from the application.

Pay attention to SPI files; exclude or replace libraries that introduce unwanted service implementations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javamavenclassloaderSpringBootGsonDependency Conflict
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.