jeecgboot/JeecgBoot · error · IllegalArgumentException
非法的任务类:${classname},必须实现 org.quartz.Job 接口
Error message
非法的任务类:${classname},必须实现 org.quartz.Job 接口 What it means
The second guard in getClass(): after the whitelist passes and Class.forName succeeds, the loaded class must be assignable to org.quartz.Job. This prevents scheduling arbitrary classes (e.g. a service bean or a class implementing a custom interface) that the Quartz scheduler cannot execute.
Source
Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/service/impl/QuartzJobServiceImpl.java:190
log.error(e.getMessage(), e);
throw new JeecgBootException("删除定时任务失败");
}
}
/**
* 安全加载Job类:仅允许 org.jeecg. 包下的类,且必须实现 org.quartz.Job 接口
*/
private static Job getClass(String classname) throws Exception {
// 包名白名单校验,防止任意类实例化导致RCE
if (classname == null || !classname.startsWith("org.jeecg.")) {
throw new IllegalArgumentException("非法的任务类名:" + classname + ",仅允许 org.jeecg 包下的Job类");
}
//update-begin---author:scott ---date:20260416 for:【PR#9538】Class.forName使用上下文类加载器,增强部署兼容性-----------
Class<?> clazz = Class.forName(classname, true, Thread.currentThread().getContextClassLoader());
//update-end---author:scott ---date:20260416 for:【PR#9538】Class.forName使用上下文类加载器,增强部署兼容性-----------
// 校验是否实现了 org.quartz.Job 接口
if (!Job.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException("非法的任务类:" + classname + ",必须实现 org.quartz.Job 接口");
}
return (Job) clazz.getDeclaredConstructor().newInstance();
}
}
View on GitHub (pinned to 96fb33f5ec)
Solutions
- Make the class implement org.quartz.Job (override execute(JobExecutionContext)) or extend a Job base such as QuartzJobBean.
- Point sys_quartz_job.job_class_name at the class that already implements Job.
Example fix
// before
public class ReportTask {
public void run() { ... }
}
// after
public class ReportTask implements org.quartz.Job {
@Override public void execute(JobExecutionContext ctx) { run(); }
public void run() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the class implements Job before scheduling.
Class<?> c = Class.forName(jobClassName);
if (!org.quartz.Job.class.isAssignableFrom(c)) {
throw new IllegalArgumentException(jobClassName + " 必须实现 org.quartz.Job");
} Type guard
public static boolean implementsJob(String name) {
try {
return org.quartz.Job.class.isAssignableFrom(
Class.forName(name, false, Thread.currentThread().getContextClassLoader()));
} catch (Throwable t) { return false; }
} Try / catch
try {
quartzJobService.schedulerAdd(job);
} catch (JeecgBootException e) {
if (e.getMessage() != null && e.getMessage().contains("必须实现 org.quartz.Job")) {
return Result.error("所选类未实现 Job 接口, 无法调度");
}
throw e;
} Prevention
- Create job classes from a Job base template so the interface is never forgotten.
- Run an automated check that all scheduled job classes implement Job at build time.
When it happens
Trigger: A jobClassName that resolves to an org.jeecg.* class which does NOT implement org.quartz.Job — e.g. a plain @Service bean, an entity, or a class implementing only java.lang.Runnable.
Common situations: A developer wrote the job logic as a method on an existing service rather than a dedicated Job class; the class was refactored and the `implements Job` clause dropped; pointing the scheduler at a DTO/entity by mistake.
Related errors
- 非法的任务类名:${classname},仅允许 org.jeecg 包下的Job类
- 后台找不到该类名:${jobClassName}
- 请注意,将要排序的列字段不存在:${column}
- 未获取到用户
- Illegal access to path outside of base directory.
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/26ad1404df5d41a9.
Report an issue: GitHub.