{"record":{"id":"c6ab835da98bec87","repo":"quarkusio/quarkus","slug":"class-has-to-be-an-interface","errorCode":null,"errorMessage":"${class} has to be an interface","messagePattern":"(.+?) has to be an interface","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/SpringDataRestProcessor.java","lineNumber":163,"sourceCode":"        Set<ClassInfo> result = new LinkedHashSet<>();\n        for (DotName repositoryInterface : repositoryInterfaces) {\n            for (ClassInfo classInfo : indexView.getKnownDirectImplementors(repositoryInterface)) {\n                if (!hasImplementors(indexView, classInfo) && !EXCLUDED_INTERFACES.contains(classInfo.name())) {\n                    validateResource(classInfo);\n                    result.add(classInfo);\n                }\n            }\n        }\n        return result;\n    }\n\n    private boolean hasImplementors(IndexView index, ClassInfo classInfo) {\n        return !index.getKnownDirectImplementors(classInfo.name()).isEmpty();\n    }\n\n    private void validateResource(ClassInfo classInfo) {\n        if (!Modifier.isInterface(classInfo.flags())) {\n            throw new RuntimeException(classInfo.name() + \" has to be an interface\");\n        }\n    }\n\n    private List<Type> getGenericTypes(ClassInfo classInfo) {\n        return classInfo.interfaceTypes()\n                .stream()\n                .findFirst()\n                .orElseThrow(() -> new RuntimeException(classInfo.toString() + \" does not have generic types\"))\n                .asParameterizedType()\n                .arguments();\n    }\n}\n","sourceCodeStart":145,"sourceCodeEnd":176,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/SpringDataRestProcessor.java#L145-L176","documentation":"Spring Data REST in Quarkus only supports repository interfaces; the extension validates every candidate resource/repository class before generating implementations. If the class selected as a resource (e.g., annotated or picked up as a Spring Data repository) is a concrete class or enum rather than an interface, the build fails with this RuntimeException.","triggerScenarios":"A class (not interface) is picked up by getRepositoriesToImplement — typically a concrete class accidentally annotated/registered as a Spring Data repository, or a base class extended instead of an interface in the repository hierarchy.","commonSituations":"Migrating Spring code where a repository was a class; accidentally annotating an entity/service with a repository stereotype; generics causing the processor to select the wrong class from the index.","solutions":["Convert the repository to a Java interface extending a Spring Data interface (e.g., JpaRepository)","Remove repository stereotypes from concrete classes; keep them only on interfaces","If it's a custom base repository, define it as an interface and implement defaults elsewhere","Check for accidental class/interface mix-up when refactoring"],"exampleFix":"// before\npublic class UserRepo extends JpaRepository<User, Long> {} // class\n\n// after\npublic interface UserRepo extends JpaRepository<User, Long> {}","handlingStrategy":"validation","validationCode":"// Compile-time guard:\n// interfaces only:\nif (!UserRepo.class.isInterface()) {\n    throw new IllegalStateException(\"Spring Data repositories must be interfaces\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare repositories as interfaces extending Spring Data interfaces","Never put repository stereotypes on concrete classes","Code-review repository declarations after Spring migrations","Use an ArchUnit rule: classes annotated with @Repository must be interfaces (except JPA exception-translation usage)"],"tags":["quarkus","spring-data-rest","build-time","interface","validation"],"backgroundTag":"repository-must-be-interface","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}