{"record":{"id":"4c3a7dd0ddc49225","repo":"hibernate/hibernate-orm","slug":"class-s-declares-both-get-s-and-is","errorCode":null,"errorMessage":"Class<?> '%s' declares both 'get' [%s] and 'is' [%s] variants of getter for property '%s'","messagePattern":"Class<\\?> '(.+?)' declares both 'get' \\[(.+?)\\] and 'is' \\[(.+?)\\] variants of getter for property '(.+?)'","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java","lineNumber":581,"sourceCode":"\t\t\t\t// No such method should throw the caught exception.  So if we get here, there was\n\t\t\t\t// such a method.\n\t\t\t\tcheckGetAndIsVariants( containerClass, propertyName, getMethod, isMethod );\n\t\t\t}\n\t\t}\n\t\tcatch (NoSuchMethodException ignore) {\n\t\t}\n\t}\n\n\n\tpublic static void checkGetAndIsVariants(\n\t\t\tClass<?> containerClass,\n\t\t\tString propertyName,\n\t\t\tMethod getMethod,\n\t\t\tMethod isMethod) {\n\t\t// Check the return types.  If they are the same, its ok.  If they are different\n\t\t// we are in a situation where we could not reasonably know which to use.\n\t\tif ( !isMethod.getReturnType().equals( getMethod.getReturnType() ) ) {\n\t\t\tthrow new MappingException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Class<?> '%s' declares both 'get' [%s] and 'is' [%s] variants of getter for property '%s'\",\n\t\t\t\t\t\t\tcontainerClass.getName(),\n\t\t\t\t\t\t\tgetMethod,\n\t\t\t\t\t\t\tisMethod,\n\t\t\t\t\t\t\tpropertyName\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic static void verifyNoGetVariantExists(\n\t\t\tClass<?> containerClass,\n\t\t\tString propertyName,\n\t\t\tMethod isMethod,\n\t\t\tString stemName) {\n\t\t// verify that the Class<?> does not also define a method with the same stem name with 'is'","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java#L563-L599","documentation":"When resolving a property, Hibernate can discover both a getFoo() and an isFoo() variant. ReflectHelper.checkGetAndIsVariants accepts the pair only when both methods declare exactly the same return type; otherwise it throws MappingException because there is no way to decide which accessor defines the property's type. Boolean and primitive boolean are different Class objects, so a wrapper/primitive mix between the two forms is enough to fail.","triggerScenarios":"A mapped class (or a class inspected via ReflectHelper.getGetter) declares both getX() and isX() with different return types, e.g. Boolean getDone() plus boolean isDone(), or int getReady() plus boolean isReady(). The check runs while property accessors are built during metadata/SessionFactory creation.","commonSituations":"Accessors written at different times by different tools (IDE generation plus a later hand-written is-getter); wrapper Boolean on one accessor and primitive boolean on the other; copy-pasted DTOs promoted to @Embeddable; Lombok-generated getter plus a manually added is-getter.","solutions":["Delete one of the two accessors so a single getter form remains for the property.","Make both return types identical (both Boolean or both boolean).","Rename one accessor so it is no longer the same JavaBean property and, on mapped classes, exclude it with @Transient."],"exampleFix":"// before\npublic class Task {\n    public Boolean getDone() { return done; } // wrapper\n    public boolean isDone() { return done; }  // primitive -> MappingException\n}\n\n// after\npublic class Task {\n    public boolean isDone() { return done; }\n}","handlingStrategy":"validation","validationCode":"static List<String> findConflictingGetAndIsVariants(Class<?> clazz) {\n    java.util.List<String> conflicts = new java.util.ArrayList<>();\n    for (var is : clazz.getMethods()) {\n        String n = is.getName();\n        if (!n.startsWith(\"is\") || n.length() <= 2 || is.getParameterCount() != 0) continue;\n        String getterName = \"get\" + Character.toUpperCase(n.charAt(2)) + n.substring(3);\n        for (var get : clazz.getMethods()) {\n            if (get.getName().equals(getterName) && get.getParameterCount() == 0\n                    && !get.getReturnType().equals(is.getReturnType())) {\n                conflicts.add(getterName + \"/\" + n);\n            }\n        }\n    }\n    return conflicts;\n}","typeGuard":null,"tryCatchPattern":"try {\n    SessionFactory sf = metadata.buildSessionFactory();\n} catch (org.hibernate.MappingException e) {\n    // message lists both method signatures; delete one accessor or unify the return types\n}","preventionTips":["Pick one accessor style per property (conventional: is-getter for primitive boolean) and enforce it in review.","Watch for wrapper/primitive boolean mixups between get and is forms of the same property.","Run a bean-consistency lint over entity classes before every build."],"tags":["hibernate","reflection","mapping","javabean","boolean-getter"],"backgroundTag":"ambiguous-bean-accessors","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}