11/*
2- * Copyright (c) 2023, 2023 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2023, 2025 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2424 */
2525package com .oracle .svm .hosted .ameta ;
2626
27+ import java .lang .annotation .Annotation ;
2728import java .lang .reflect .Field ;
2829import java .util .ArrayList ;
2930import java .util .Arrays ;
5657import com .oracle .svm .hosted .substitute .AnnotationSubstitutionProcessor ;
5758import com .oracle .svm .hosted .substitute .AutomaticUnsafeTransformationSupport ;
5859import com .oracle .svm .hosted .substitute .FieldValueTransformation ;
60+ import com .oracle .svm .util .ClassUtil ;
5961import com .oracle .svm .util .ReflectionUtil ;
6062
6163import jdk .graal .compiler .nodes .ValueNode ;
@@ -376,13 +378,15 @@ private static JavaConstant interceptWordField(AnalysisField field, JavaConstant
376378 private static FieldValueComputer createFieldValueComputer (AnalysisField field ) {
377379 UnknownObjectField unknownObjectField = field .getAnnotation (UnknownObjectField .class );
378380 if (unknownObjectField != null ) {
381+ checkMisplacedAnnotation (field .getStorageKind ().isObject (), field );
379382 return new FieldValueComputer (
380383 ReflectionUtil .newInstance (unknownObjectField .availability ()),
381384 extractAnnotationTypes (field , unknownObjectField .types (), unknownObjectField .fullyQualifiedTypes ()),
382385 unknownObjectField .canBeNull ());
383386 }
384387 UnknownPrimitiveField unknownPrimitiveField = field .getAnnotation (UnknownPrimitiveField .class );
385388 if (unknownPrimitiveField != null ) {
389+ checkMisplacedAnnotation (field .getStorageKind ().isPrimitive (), field );
386390 return new FieldValueComputer (
387391 ReflectionUtil .newInstance (unknownPrimitiveField .availability ()),
388392 List .of (field .getType ().getJavaClass ()),
@@ -391,6 +395,31 @@ private static FieldValueComputer createFieldValueComputer(AnalysisField field)
391395 return null ;
392396 }
393397
398+ /**
399+ * For compatibility reasons, we cannot unify {@link UnknownObjectField} and
400+ * {@link UnknownPrimitiveField} into a single annotation, but we can at least notify the
401+ * developers if the annotation is misplaced, e.g. {@link UnknownObjectField} is used on a
402+ * primitive field and vice versa.
403+ */
404+ private static void checkMisplacedAnnotation (boolean condition , AnalysisField field ) {
405+ if (!condition ) {
406+ String fieldType ;
407+ Class <? extends Annotation > expectedAnnotationType ;
408+ Class <? extends Annotation > usedAnnotationType ;
409+ if (field .getStorageKind ().isObject ()) {
410+ fieldType = "object" ;
411+ expectedAnnotationType = UnknownObjectField .class ;
412+ usedAnnotationType = UnknownPrimitiveField .class ;
413+ } else {
414+ fieldType = "primitive" ;
415+ expectedAnnotationType = UnknownPrimitiveField .class ;
416+ usedAnnotationType = UnknownObjectField .class ;
417+ }
418+ throw UserError .abort ("@%s should not be used on %s fields, use @%s on %s instead." , ClassUtil .getUnqualifiedName (usedAnnotationType ),
419+ fieldType , ClassUtil .getUnqualifiedName (expectedAnnotationType ), field .format ("%H.%n" ));
420+ }
421+ }
422+
394423 private static List <Class <?>> extractAnnotationTypes (AnalysisField field , Class <?>[] types , String [] fullyQualifiedTypes ) {
395424 List <Class <?>> annotationTypes = new ArrayList <>(Arrays .asList (types ));
396425 for (String annotationTypeName : fullyQualifiedTypes ) {
0 commit comments