{"record":{"id":"60e4194695170066","repo":"quarkusio/quarkus","slug":"class-configobjectclassstr-which-is-anno","errorCode":null,"errorMessage":"Class '' + configObjectClassStr + '' which is annotated with '' + ConfigurationPropertiesProcessor.CONFIGURATION_PROPERTIES + '' must be public, as must be the case for all of its super classes","messagePattern":"Class '' \\+ configObjectClassStr \\+ '' which is annotated with '' \\+ ConfigurationPropertiesProcessor\\.CONFIGURATION_PROPERTIES \\+ '' must be public, as must be the case for all of its super classes","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java","lineNumber":256,"sourceCode":"            ConfigMapping.NamingStrategy namingStrategy,\n            boolean failOnMismatchingMember,\n            ConfigurationPropertiesMetadataBuildItem.InstanceFactory instanceFactory, BlockCreator bc, Expr configParam) {\n        String configObjectClassStr = configClassInfo.name().toString();\n        LocalVar configObject;\n        if (instanceFactory == null) {\n            configObject = bc.localVar(\"configObject\", bc.new_(ConstructorDesc.of(ClassDesc.of(configObjectClassStr))));\n        } else {\n            configObject = bc.localVar(\"configObject\", instanceFactory.apply(bc, configObjectClassStr));\n        }\n\n        // Fields with a default value will be removed from this list at the end of the method.\n        List<ConfigPropertyBuildItemCandidate> configPropertyBuildItemCandidates = new ArrayList<>();\n\n        // go up the class hierarchy until we reach Object\n        ClassInfo currentClassInHierarchy = configClassInfo;\n        while (true) {\n            if (!Modifier.isPublic(currentClassInHierarchy.flags())) {\n                throw new IllegalArgumentException(\n                        \"Class '\" + configObjectClassStr + \"' which is annotated with '\"\n                                + ConfigurationPropertiesProcessor.CONFIGURATION_PROPERTIES\n                                + \"' must be public, as must be the case for all of its super classes\");\n            }\n\n            // For each field of the class try to pull it out of MP Config and call the corresponding setter\n            List<FieldInfo> fields = currentClassInHierarchy.fields();\n            for (FieldInfo field : fields) {\n                if (Modifier.isStatic(field.flags())) { // nothing we need to do about static fields\n                    continue;\n                }\n                AnnotationInstance configPropertyAnnotation = field.annotation(DotNames.CONFIG_PROPERTY);\n                if (configPropertyAnnotation != null) {\n                    AnnotationValue configPropertyDefaultValue = configPropertyAnnotation.value(\"defaultValue\");\n                    if ((configPropertyDefaultValue != null)\n                            && !configPropertyDefaultValue.asString().equals(ConfigProperty.UNCONFIGURED_VALUE)) {\n                        LOGGER.warn(\n                                \"'defaultValue' of '@ConfigProperty' is ignored when added to a field of a class annotated with '@ConfigProperties'. Offending field is '\"","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java#L238-L274","documentation":"Configuration properties classes are instantiated reflectively at build time and (in native mode) must be visible to reflection. The @ConfigurationProperties class — and every class in its hierarchy up to Object — must be public; a package-private or protected class breaks instantiation and is rejected at build.","triggerScenarios":"populateConfigObject walks the class hierarchy of the config object class and throws as soon as any currentClassInHierarchy fails Modifier.isPublic(...).","commonSituations":"Nesting a package-private properties class inside another class; narrowing visibility of a superclass during refactoring; Kotlin/Java inner classes with restricted access.","solutions":["Make the @ConfigurationProperties class public.","Make every non-public superclass in its hierarchy public.","Move a previously nested/inner properties class out to a top-level public class."],"exampleFix":"// before\nclass AppProps { ... }\n// after\npublic class AppProps { ... }","handlingStrategy":"validation","validationCode":"static void checkPublicHierarchy(Class<?> c) {\n    for (Class<?> k = c; k != Object.class; k = k.getSuperclass()) {\n        if (!Modifier.isPublic(k.getModifiers()))\n            throw new IllegalArgumentException(k + \" must be public\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare all @ConfigurationProperties classes and their superclasses public.","Avoid nested package-private config POJOs.","Check visibility after refactors that move config classes between packages."],"tags":["quarkus","spring-boot","configuration-properties","visibility"],"backgroundTag":"config-class-not-public","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"}