Skip to content

Resolving "A Java agent has been loaded dynamically" Warning in Java 21

Problem Statement

When upgrading Java projects from JDK 17 to 21, you may encounter warnings during JUnit test execution in IDEs like IntelliJ or Eclipse:

WARNING: A Java agent has been loaded dynamically (...\byte-buddy-agent-1.14.9.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release

This occurs due to JEP 451, which restricts dynamic agent loading for enhanced security. Libraries that attach Java agents at runtime (like Mockito, Byte Buddy, or ASM) trigger this warning. While your tests may still pass, this workflow will break in future Java versions when dynamic loading becomes prohibited by default.

Instead of temporarily allowing dynamic loading, configure your project to load agents on JVM startup using the standard -javaagent flag. Implement these solutions based on your test execution method.

For Maven Projects

Add the agent path directly in pom.xml using the maven-surefire-plugin:

xml
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
        <argLine>
          -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar
        </argLine>
      </configuration>
    </plugin>
  </plugins>
</build>

Ensure ${mockito.version} is defined as a property in your POM:

xml
<properties>
  <mockito.version>5.12.0</mockito.version>
</properties>

WARNING

Avoid using ${org.mockito:mockito-core:jar} property references. While they seem cleaner, they cause issues in IDEs.

For Gradle Projects

Use the javaagent flag in your test configuration:

groovy
test {
  jvmArgs "-javaagent:${configurations.testRuntimeClasspath.find { it.name.contains('mockito-core') }}"
}

Alternatively, use the javaagent-test Gradle plugin for better maintainability:

groovy
plugins {
  id("com.ryandens.javaagent-test") version "0.8.0"
}

dependencies {
  testJavaagent("net.bytebuddy:byte-buddy-agent:1.15.11")
}

IDE-Specific Workarounds

IntelliJ Configuration

  1. Open Run > Edit Configurations...
  2. Select your JUnit template under Templates > JUnit
  3. Add to VM options:
    -javaagent:$MAVEN_REPOSITORY$/org/mockito/mockito-core/5.14.2/mockito-core-5.14.2.jar

IntelliJ VM options configuration

TIP

Manual path update is required when changing Mockito versions. To apply to existing configurations, duplicate them after changing the template.

Eclipse Configuration

  1. Open Run > Run Configurations...
  2. Select your JUnit configuration
  3. In Arguments tab, add to VM arguments:
    -javaagent:${env_var:userprofile}\.m2\repository\org\mockito\mockito-core\5.14.2\mockito-core-5.14.2.jar
  4. Use your actual Mockito version in the path

Solutions to Avoid

Anti-patterns

These approaches simply suppress the warning without fixing the underlying issue:

xml
<!-- Maven anti-pattern -->
<argLine>-XX:+EnableDynamicAgentLoading</argLine>
groovy
// Gradle anti-pattern
test {
  jvmArgs "-XX:+EnableDynamicAgentLoading"
}

Setting JDK_JAVA_OPTIONS globally is especially problematic as it hides the issue for all projects.

Why Proper Loading Matters

  • Security: Prevents unauthorized agent attachment
  • Future compatibility: Works when dynamic loading gets disabled
  • Visibility: Confirms valid agents are intentionally loaded
  • Performance: Avoids instrumentation conflicts

Troubleshooting

If the -javaagent path doesn't resolve:

  1. Verify the exact filename in your repository
  2. Use mvn dependency:properties to debug paths
  3. For non-Mockito agents, adjust the JAR path (e.g., byte-buddy-agent.jar)
  4. Clear IDE caches after configuration changes

Conclusion

Loading Java agents properly solves this warning permanently. Always define agents through -javaagent in your build configuration or IDE settings instead of allowing dynamic loading. This ensures compatibility with current and future Java versions while maintaining secure development practices.