Debugging Excel Parsing Errors with Arthas and Building a Custom Java Agent
This article walks through diagnosing a hidden Excel parsing exception using Arthas, identifies the root cause in header mapping logic, and then explains Java Agent fundamentals before providing a step‑by‑step demo that injects custom code into a running JVM.
Problem Overview
In a project that uses com.github.dreamroute:excel-helper to parse Excel files, the catch block only logs e.getMessage(), which hides the full stack trace. This makes reproducing the error difficult.
Investigation with Arthas
Install Arthas on the production server (see https://arthas.aliyun.com/doc/install-detail.html).
Run the following watch command to monitor ExcelHelper.importFromFile and print parameters and thrown exceptions:
watch com.github.dreamroute.excel.helper.ExcelHelper importFromFile '{params,throwExp}' -e -x 3The command captures the exception stack (see image).
Root Cause Analysis
The headerInfoMap may contain incorrect data.
The columnIndex of a cell might exceed the valid range.
Local testing shows the second case is unlikely, so the focus is on the first.
Map<Integer, HeaderInfo> headerInfoMap = processHeaderInfo(rows, cls);The processHeaderInfo method reads the first row of the Excel file and builds the map:
public static Map<Integer, HeaderInfo> processHeaderInfo(Iterator<Row> rows, Class<?> cls) {
if (rows.hasNext()) {
Row header = rows.next();
return CacheFactory.findHeaderInfo(cls, header);
}
return new HashMap<>(0);
}
public static Map<Integer, HeaderInfo> findHeaderInfo(Class<?> cls, Row header) {
Map<Integer, HeaderInfo> headerInfo = HEADER_INFO.get(cls);
if (MapUtils.isEmpty(headerInfo)) {
headerInfo = ClassAssistant.getHeaderInfo(cls, header);
HEADER_INFO.put(cls, headerInfo);
}
return headerInfo;
}The HEADER_INFO cache is stored in CacheFactory. If the cache contains wrong entries, every subsequent Excel upload fails.
Using an OGNL expression to inspect the cache reveals only four entries instead of the expected six columns:
ognl '#value=new com.tom.dto.ExcelDTO(),#[email protected]@HEADER_INFO,#valueMap.get(#value.getClass()).entrySet().iterator.{#this.value.name}'The missing entries explain the exception. A colleague confirmed that the first uploaded file was malformed, which corrupted the cache.
Arthas Internals – Java Agent Fundamentals
Arthas attaches a Java Agent to a running JVM. A Java Agent can be loaded at JVM startup via -javaagent or attached at runtime using the Attach API, providing dynamic instrumentation.
Key Concepts
JVMTI (JVM Tool Interface): Event‑driven native interface for JVM extensions.
JVMTI Agent: Native library that uses JVMTI and the Attach mechanism to load agents.
JPLISAgent: Initializes agents written with the Java Instrumentation API.
VirtualMachine: Provides attach and loadAgent methods to inject agents at runtime.
Instrumentation: Allows bytecode transformation before class loading ( premain) or after ( agentmain).
Demo: Building a Simple Java Agent
The demo uses Javassist to insert custom logic before and after a target method.
1. Define the Agent
/**
* AgentMain
*/
public class AgentMain {
public static void agentmain(String agentArgs, Instrumentation instrumentation)
throws UnmodifiableClassException, ClassNotFoundException {
instrumentation.addTransformer(new InterceptorTransformer(agentArgs), true);
Class clazz = Class.forName(agentArgs.split(",")[1]);
instrumentation.retransformClasses(clazz);
}
}
public class InterceptorTransformer implements ClassFileTransformer {
private String agentArgs;
public InterceptorTransformer(String agentArgs) { this.agentArgs = agentArgs; }
@Override
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className != null && className.indexOf("/") != -1) {
className = className.replaceAll("/", ".");
}
try {
CtClass cc = ClassPool.getDefault().get(className);
CtMethod m = cc.getDeclaredMethod(agentArgs.split(",")[2]);
m.insertBefore("{ System.out.println(\"=========开始执行=========\"); }");
m.insertAfter("{ System.out.println(\"=========结束执行=========\"); }");
return cc.toBytecode();
} catch (Exception e) { }
return null;
}
}2. Maven Manifest Configuration
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Agent-Class>com.tom.mdc.AgentMain</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>3. Attach to Target JVM
import com.sun.tools.attach.VirtualMachine;
import java.io.IOException;
public class AttachMain {
public static void main(String[] args) {
VirtualMachine vm = null;
try {
vm = VirtualMachine.attach(args[0]);
vm.loadAgent("target/agent-demo-1.0-SNAPSHOT.jar", String.join(",", args));
} catch (Exception e) {
if (vm != null) {
try { vm.detach(); } catch (IOException ex) { ex.printStackTrace(); }
}
}
}
}4. Test Application
package com.tom.mdc;
import java.lang.management.ManagementFactory;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class PrintParamTarget {
public static void main(String[] args) {
System.out.println(ManagementFactory.getRuntimeMXBean().getName());
Random random = new Random();
while (true) {
int sleepTime = 5 + random.nextInt(5);
running(sleepTime);
}
}
private static void running(int sleepTime) {
try { TimeUnit.SECONDS.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("running sleep time " + sleepTime);
}
}This demo shows how to attach an agent at runtime, transform a method, and observe the injected logging output.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
