
本文介绍如何通过自定义 visitor adapter,在 jsqlparser 中实现“未实现功能即报错”的严格解析策略,避免不支持的 sql 语句(如 insert、group by)被静默忽略。
本文介绍如何通过自定义 visitor adapter,在 jsqlparser 中实现“未实现功能即报错”的严格解析策略,避免不支持的 sql 语句(如 insert、group by)被静默忽略。
JSqlParser 默认提供的 *VisitorAdapter(例如 StatementVisitorAdapter、ExpressionVisitorAdapter)为所有访问方法提供了空实现,因此当解析器遇到未显式覆盖的方法(如 visit(Insert insert) 或 visit(GroupByElement groupBy))时,不会抛出异常,而是直接跳过——这对快速原型开发友好,但对构建强约束型轻量数据库而言存在安全隐患:非法语法可能被静默接受,导致行为不可预期。
要实现“仅允许白名单功能”的严格校验,推荐方案是编写自定义 Adapter 类,将所有默认访问方法统一改为抛出 UnsupportedOperationException。这样,只要解析树中出现未被显式处理的节点类型,就会立即中断并报错。
以下是一个典型实现示例(以 StatementVisitor 为例):
public class StrictStatementVisitor implements StatementVisitor {
@Override
public void visit(Select select) {
// ✅ 显式支持 SELECT
select.getSelectBody().accept(new StrictSelectBodyVisitor());
}
@Override
public void visit(Insert insert) {
throw new UnsupportedOperationException("INSERT statements are not supported");
}
@Override
public void visit(Update update) {
throw new UnsupportedOperationException("UPDATE statements are not supported");
}
@Override
public void visit(Delete delete) {
throw new UnsupportedOperationException("DELETE statements are not supported");
}
// 其他 Statement 子类同理:Create, Drop, With, etc.
// 所有未明确支持的类型均抛出异常
}
配套的 StrictSelectBodyVisitor 可沿用相同原则,例如:
public class StrictSelectBodyVisitor implements SelectBodyVisitor {
@Override
public void visit(SetOperationList setOpList) {
throw new UnsupportedOperationException("UNION/INTERSECT/EXCEPT not supported");
}
@Override
public void visit(PlainSelect plainSelect) {
if (plainSelect.getGroupBy() != null) {
throw new UnsupportedOperationException("GROUP BY is not supported");
}
if (plainSelect.getHaving() != null) {
throw new UnsupportedOperationException("HAVING clause is not supported");
}
// 仅递归处理支持的子节点,如 SelectItems、FromItem、Where 等
plainSelect.getSelectItems().forEach(item -> item.accept(new StrictSelectItemVisitor()));
if (plainSelect.getFromItem() != null) {
plainSelect.getFromItem().accept(new StrictFromItemVisitor());
}
if (plainSelect.getWhere() != null) {
plainSelect.getWhere().accept(new StrictExpressionVisitor());
}
}
}
⚠️ 注意事项:
- 不要继承 StatementVisitorAdapter 并仅重写部分方法——它的空实现会掩盖缺失支持;
- 建议使用 IDE 自动生成接口全部方法,再逐个审查并填充逻辑或异常,确保无遗漏;
- 可配合 CCJSqlParserManager 的 parse() 方法捕获 JSQLParserException,并在外层统一处理业务级拒绝响应;
- 对于复杂表达式(如函数调用、子查询),建议在 ExpressionVisitor 层也采用相同严格策略,防止 Function, SubSelect, CaseExpression 等被忽略。
通过该方式,你将获得一个可预测、易维护、面向安全边界的 SQL 解析层:每一条被接受的 SQL 都明确经过你的逻辑校验,每一个被拒绝的语法都有清晰的错误提示——这正是构建可靠嵌入式数据库解析器的关键第一步。











