{"record":{"id":"b296455df64d4ed3","repo":"oracle/graal","slug":"s-is-not-an-annotation-interface","errorCode":null,"errorMessage":"%s is not an annotation interface","messagePattern":"(.+?) is not an annotation interface","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueSupport.java","lineNumber":67,"sourceCode":"/**\n * Support for parsing class file annotation attributes.\n */\npublic class AnnotationValueSupport {\n\n    /**\n     * Gets the annotation directly present on {@code annotated} whose type is\n     * {@code annotationType}. Class initialization is not triggered for enum types referenced by\n     * the returned annotation. This method ignores inherited annotations.\n     *\n     * @param annotationType the type object corresponding to the annotation interface type\n     * @return {@code annotated}'s annotation for the specified annotation type if directly present\n     *         on this element, else null\n     * @throws IllegalArgumentException if {@code annotationType} is not an annotation interface\n     *             type\n     */\n    public static AnnotationValue getDeclaredAnnotationValue(ResolvedJavaType annotationType, Annotated annotated) {\n        if (!annotationType.isAnnotation()) {\n            throw new IllegalArgumentException(annotationType.toJavaName() + \" is not an annotation interface\");\n        }\n        return getDeclaredAnnotationValues(annotated).get(annotationType);\n    }\n\n    /**\n     * Checks if an annotation of the specified type is directly present on the given\n     * {@code annotated} element. Class initialization is not triggered for enum types referenced by\n     * the returned annotation. This method ignores inherited annotations.\n     *\n     * @param annotationType the type object corresponding to the annotation interface type\n     * @return true if an annotation of the specified type is directly present on the given\n     *         {@code annotated} element\n     * @throws IllegalArgumentException if {@code annotationType} is not an annotation interface\n     *             type\n     */\n    public static boolean isAnnotationPresent(ResolvedJavaType annotationType, Annotated annotated) {\n        return getDeclaredAnnotationValue(annotationType, annotated) != null;\n    }","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueSupport.java#L49-L85","documentation":"checkNonExistingGlobalReference scans all registered Cleaner entries and throws IllegalArgumentException if an identical object already has a global JNI reference (checked via JNI IsSameObject). The library intentionally avoids duplicate global refs for the same host object, because each global ref is a leak-prone native resource and the cleaner registry assumes one entry per object.","triggerScenarios":"Calling NewGlobalRef (the JNIUtil helper that routes through this check) twice for the same host object without deleting the first reference; retry paths that re-create a global ref after a failure without cleaning up; two features both pinning the same well-known object (e.g. the same class or exception instance).","commonSituations":"Idempotency bugs in JNI glue code where a setup routine runs twice; concurrent initialization racing to pin the same singleton object; missing DeleteGlobalRef on a previous reference before re-creating it.","solutions":["Track existing global refs and reuse them instead of creating a second one for the same object.","Delete the old global reference (JNIUtil.release / DeleteGlobalRef) before creating a new one for the same object.","Guard creation code with a single initialization point (e.g. synchronized lazy init or a static registry keyed by object) so the same object is never registered twice."],"exampleFix":"// before\nJObject g1 = NewGlobalRef(env, obj, \"obj\");\nJObject g2 = NewGlobalRef(env, obj, \"obj\"); // throws\n\n// after\nJObject g = registry.getOrCreateGlobalRef(env, obj); // returns existing ref if IsSameObject match\n// and call JNIUtil.release(env, g) when done, before re-creating","handlingStrategy":"validation","validationCode":"// Before creating a global ref, check whether you already hold one for the same object:\nJObject existing = registry.lookupSameObject(env, candidate);\nif (existing != null && JNIUtil.IsSameObject(env, existing, candidate)) {\n    return existing; // reuse, do not create a duplicate\n}\nNewGlobalRef(env, candidate, \"name\");","typeGuard":null,"tryCatchPattern":"try {\n    NewGlobalRef(env, obj, tag);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Global JNI handle already exists\")) {\n        // fetch the existing ref from your registry instead of creating a new one\n    } else {\n        throw e;\n    }\n}","preventionTips":["Centralize global-reference creation in one registry so the same object is pinned once.","Always pair NewGlobalRef with release/DeleteGlobalRef before re-pinning the same object.","Make init code idempotent (guarded by a 'initialized' flag) so retries don't double-register."],"tags":["jni","global-reference","duplicate","resource-management"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}