{"record":{"id":"44c49514f9e386c3","repo":"Blankj/AndroidUtilCode","slug":"u-should-impl-these-apis-noimplapis-n-u-c","errorCode":null,"errorMessage":"u should impl these apis: \" + noImplApis + \"\\n u can check it in file: \" + jsonFile.toString()","messagePattern":"u should impl these apis: \" \\+ noImplApis \\+ \"\\\\n u can check it in file: \" \\+ jsonFile\\.toString\\(\\)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiPlugin.groovy","lineNumber":105,"sourceCode":"                apiImplMap.each { key, value ->\n                    implApis.put(key, value.toString())\n                }\n                apiClasses.each {\n                    if (!apiImplMap.containsKey(it)) {\n                        noImplApis.add(it)\n                    }\n                }\n                Map apiDetails = [:]\n                apiDetails.put(\"ApiUtilsClass\", apiUtilsClass)\n                apiDetails.put(\"implApis\", implApis)\n                apiDetails.put(\"noImplApis\", noImplApis)\n                String apiJson = JsonUtils.getFormatJson(apiDetails)\n                log(jsonFile.toString() + \": \" + apiJson)\n                FileUtils.write(jsonFile, apiJson)\n\n                if (noImplApis.size() > 0) {\n                    if (ext.abortOnError) {\n                        throw new Exception(\"u should impl these apis: \" + noImplApis +\n                                \"\\n u can check it in file: \" + jsonFile.toString())\n                    }\n                }\n                ApiInject.start(apiImplMap, apiUtilsTransformFile, apiUtilsClass)\n            }\n        } else {\n            throw new Exception(\"No ApiUtils of ${apiUtilsClass} in $mProject.\")\n        }\n    }\n}","sourceCodeStart":87,"sourceCodeEnd":115,"githubUrl":"https://github.com/Blankj/AndroidUtilCode/blob/7b4caf9e5440046b3fefb63b6b6e2ead7ebaf809/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiPlugin.groovy#L87-L115","documentation":"After scanning, ApiPlugin collects all XxxApi subclasses of ApiUtils.BaseApi (mApiClasses) and all @ApiUtils.Api impls (apiImplMap). Any api class with no registered impl is added to noImplApis. If noImplApis is non-empty and ext.abortOnError is true (default), it throws Exception listing the unimplemented APIs and pointing at the generated __api__.json. This is a compile-time guarantee that no missing impl reaches runtime (where ApiUtils.getApi would otherwise return null and crash later).","triggerScenarios":"Declaring `abstract class XxxApi extends ApiUtils.BaseApi` with no class annotated @ApiUtils.Api extending it; the real impl lives in a module excluded from the scan (onlyScanLibRegex/jumpScanLibRegex) or not compiled into the current variant; the impl is annotated with a wrong @Api whose descriptor does not match.","commonSituations":"An api is declared in an export module but its impl lives in a feature/pkg module not included in the current single-module debug build; impl class forgotten or not annotated; annotation import points to a different @Api.","solutions":["Add a class extending the unimplemented XxxApi, annotated @ApiUtils.Api (isMock = false), with a public no-arg constructor.","If running a single module in isolation, provide a @ApiUtils.Api(isMock = true) mock impl so the api is satisfied.","If the real impl exists but is skipped, broaden onlyScanLibRegex / remove jumpScanLibRegex so the impl's jar/module is scanned.","Temporarily set abortOnError = false to let the build proceed (the api will return null at runtime, so use this only for diagnostics)."],"exampleFix":"// before - MainApi declared but never implemented -> \"u should impl these apis\"\npublic abstract class MainApi extends ApiUtils.BaseApi {\n    public abstract MainResult startMainActivity(Context ctx, MainParam p);\n}\n\n// after - add a real impl (or a mock for isolated builds)\n@ApiUtils.Api\npublic class MainApiImpl extends MainApi {\n    public MainApiImpl() {}   // public no-arg constructor required\n    @Override\n    public MainResult startMainActivity(Context ctx, MainParam p) {\n        MainActivity.start(ctx, p);\n        return new MainResult(\"ok\");\n    }\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every class extending ApiUtils.BaseApi must have exactly one @ApiUtils.Api impl in the app build.","For isolated/single-module runs, ship a @ApiUtils.Api(isMock = true) impl in the mock source set.","Confirm impl classes are in scanned jars/modules (mind onlyScanLibRegex/jumpScanLibRegex).","Inspect the generated __api__.json after each build to catch noImplApis early."],"tags":["gradle-plugin","api","build","asm"],"backgroundTag":null,"analyzedSha":"7b4caf9e5440046b3fefb63b6b6e2ead7ebaf809","analyzedAt":"2026-08-14T02:26:54.956Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}