{"record":{"id":"cbe6676d9b6fa98d","repo":"Blankj/AndroidUtilCode","slug":"apiextension-s-apiutilsclass-is-empty","errorCode":null,"errorMessage":"ApiExtension's apiUtilsClass is empty.","messagePattern":"ApiExtension's apiUtilsClass is empty\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiPlugin.groovy","lineNumber":30,"sourceCode":"\nclass ApiPlugin extends BaseTransformPlugin<ApiExtension> {\n\n    String apiUtilsClass\n    File jsonFile\n    File apiUtilsTransformFile\n    Map<String, ApiInfo> apiImplMap = [:]\n    List<String> apiClasses = []\n\n    @Override\n    String getPluginName() {\n        return Config.EXT_NAME\n    }\n\n    @Override\n    void onScanStarted() {\n        apiUtilsClass = ext.apiUtilsClass\n        if (apiUtilsClass.trim().equals(\"\")) {\n            throw new Exception(\"ApiExtension's apiUtilsClass is empty.\")\n        }\n\n        jsonFile = new File(mProject.projectDir.getAbsolutePath(), \"__api__.json\")\n        FileUtils.write(jsonFile, \"{}\")\n    }\n\n    @Override\n    boolean isIgnoreScan(JarInput input) {\n        def jarName = input.name\n        if (jarName.contains(\"utilcode\")) {\n            return false\n        }\n\n        if (ext.onlyScanLibRegex != null && ext.onlyScanLibRegex.trim().length() > 0) {\n            return !Pattern.matches(ext.onlyScanLibRegex, jarName)\n        }\n\n        if (ext.jumpScanLibRegex != null && ext.jumpScanLibRegex.trim().length() > 0) {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/Blankj/AndroidUtilCode/blob/7b4caf9e5440046b3fefb63b6b6e2ead7ebaf809/plugin/api-gradle-plugin/src/main/java/com/blankj/api/ApiPlugin.groovy#L12-L48","documentation":"ApiPlugin.onScanStarted() reads ext.apiUtilsClass (ApiExtension default \"com.blankj.utilcode.util.ApiUtils\"). If, after trim(), the value is empty, it throws Exception. The plugin needs the fully-qualified ApiUtils class name to know which class to inject the registered impls into during transform.","triggerScenarios":"Configuring the api{} DSL with apiUtilsClass set to an empty string or whitespace, e.g. api { apiUtilsClass \"\" }; or assigning a property that resolves to a blank value.","commonSituations":"Pointing the api extension at a custom ApiUtils class but leaving the path blank; a typo or cleared property; copy-pasting a config snippet that omitted the value.","solutions":["Set apiUtilsClass to the fully-qualified name of your ApiUtils class, e.g. api { apiUtilsClass 'com.blankj.utilcode.util.ApiUtils' }.","If you use AndroidUtilCode's built-in ApiUtils, remove the apiUtilsClass override so the default applies.","Make sure no build logic assigns an empty/whitespace string to ext.apiUtilsClass."],"exampleFix":"// before\napi {\n    apiUtilsClass \"\"   // -> \"ApiExtension's apiUtilsClass is empty.\"\n}\n\n// after\napi {\n    apiUtilsClass \"com.blankj.utilcode.util.ApiUtils\"\n}\n// or omit the api{} block entirely to use the default","handlingStrategy":"validation","validationCode":"afterEvaluate {\n    def extApi = project.extensions.findByName('api')\n    if (extApi == null || !extApi.apiUtilsClass?.trim()) {\n        throw new GradleException(\"api { apiUtilsClass '...' } must be set and non-blank.\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass a concrete fully-qualified class name to apiUtilsClass, never blank.","If unsure, omit the api{} block and rely on the default com.blankj.utilcode.util.ApiUtils.","Add an afterEvaluate assertion so a blank value fails your build early with a clear message."],"tags":["gradle-plugin","api","config","build"],"backgroundTag":null,"analyzedSha":"7b4caf9e5440046b3fefb63b6b6e2ead7ebaf809","analyzedAt":"2026-08-14T02:26:54.956Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}