Errors and Diagnostics¶
Because LarkBatis shifts validation from runtime to compile time, most configuration errors surface as build errors before tests or deployment even run.
Build-Time Errors¶
Compile-time errors report the exact mapper method, XML line, and recommended fix:
| Compile Error | Resolution |
|---|---|
#{} parameter name cannot be resolved |
Check parameter spelling or annotate with @Param. If parameters are called arg0, see Troubleshooting |
Plain String parameter bound to ${} |
Use SqlFragment, closed-value types (enums/integers), or @OrderBy(allowed = {...}) |
test="count" truthiness |
Use explicit comparison (count != 0, user != null, !list.isEmpty()) |
Unsupported expression in test= |
Simplify the test condition or compute the boolean in Java |
| Method has both annotation and XML statement, or neither | Define statement in either an annotation or XML, not both |
Method takes untyped Map or Object parameter |
Use a concrete typed parameter object or @Param annotations |
useGeneratedKeys = true missing keyProperty |
Specify target property name in keyProperty |
Count mismatch between keyColumn and keyProperty |
Ensure both lists have the same number of comma-separated entries |
@PadPow2 on non-IN <foreach> or on INSERT |
Remove @PadPow2. Padding is only valid for simple IN clauses |
| Batch method contains dynamic SQL tags | Batch inserts must use an invariant SQL statement string |
Stream<T> return over nested <resultMap> |
Return List<T>, or stream flat rows and group them in memory |
| Result map nested more than one level | Limit join nesting to one level per query |
select= attribute on <association> / <collection> |
Join the tables in SQL instead of using nested queries |
Missing <id> column in nested result map query |
Include parent ID column in the SELECT list for row grouping |
Type alias used in type / ofType / javaType |
Use fully-qualified class names |
Computed expression in <include refid="..."> |
Use a literal static fragment refid |
| Result class lacks no-arg constructor or setters | Add a public no-arg constructor and setters (or fix Lombok annotation processor ordering) |
Build-Time Warnings¶
These warnings highlight potential runtime issues or suboptimal performance:
| Build Warning | Impact |
|---|---|
useGeneratedKeys without keyColumn |
Defaults to non-portable RETURN_GENERATED_KEYS. (Oracle returns ROWID, PostgreSQL returns all columns) |
| Fallback to name-based row reads | SELECT * or unaliased expressions prevent indexed reading; falls back to ResultSetMetaData lookup |
Nested result map query missing ORDER BY |
Result set must be sorted by parent key for single-pass grouping |
Column in <result> not found in SELECT list |
Property will not be populated from query results |
Mapper XML namespace belongs to another module |
XML file will be ignored during current compilation unit |
Runtime Exceptions¶
All runtime exceptions extend LarkBatisException:
LarkBatisRejectedException¶
Thrown when dynamic input fails validation against an allowed whitelist in SqlFragment.allowed(...) or @OrderBy:
The invalid value is rejected before the SQL query is constructed.
LarkBatisEmptyForeachException¶
Thrown when an empty collection is passed to an unguarded <foreach> loop:
<foreach collection="ids"> is empty in statement com.example.app.UserBatchMapper.findByIds;
wrap the loop in an <if> testing the collection if an empty one should drop the fragment instead
LarkBatisNoKeyException¶
Thrown when useGeneratedKeys = true was configured, but the JDBC driver returned an empty generated keys result set.
LarkBatisKeyCountMismatchException¶
Thrown during batch inserts when the count of returned generated keys doesn't match the number of inserted batch rows.
Statement com.example.app.OrderMapper.insertAll expected 500 generated keys
but the driver returned 1
LarkBatisUnboundedVariantsException¶
Thrown when fail-on-unbounded-fragment: true is enabled and a statement exceeds max-sql-variants:
LarkBatis statement com.example.app.UserMapper.search has produced more than 64 distinct
SQL texts; statement caches will keep growing. Prefer SqlFragment.allowed(...) or @OrderBy
over unbounded fragments.
LarkBatisRollbackOnlyException¶
Thrown when an application calls tx.commit() on a transaction that was marked rollback-only by an inner failure or unvoted scope.
Spring Exception Translation¶
When running inside Spring, SpringLarkBatisSession routes database errors through Spring's SQLExceptionTranslator (SQLExceptionSubclassTranslator by default).
JDBC errors are automatically translated into Spring's DataAccessException hierarchy (e.g. DuplicateKeyException, CannotAcquireLockException), maintaining direct compatibility with existing @ExceptionHandler and @Retryable annotations.
LarkBatis-specific validation exceptions (LarkBatisRejectedException, LarkBatisEmptyForeachException, etc.) are passed through directly.
Logging¶
LarkBatis runtime logs via java.util.logging. It avoids injecting runtime logging branches into generated method bytecode. For detailed SQL and parameter logging, configure a logging proxy at the datasource or driver level (datasource-proxy, p6spy).
Because SQL statements are generated at compile time, you can also inspect generated SQL directly in the generated Mapper$$Impl.java source files in your build directory.