JDK-7183985 : (ann) Class.getAnnotation() throws an ArrayStoreException when the annotation class not present
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 6u33,7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_7
  • CPU: generic,x86
  • Submitted: 2012-07-13
  • Updated: 2019-03-05
  • Resolved: 2018-06-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11
11 b19Fixed
Related Reports
CSR :  
Duplicate :  
Relates :  
Relates :  
Sub Tasks
JDK-8209742 :  
Description
SYNOPSIS
--------
Class.getAnnotation() throws an ArrayStoreException when the annotation class is not present in the classpath

OPERATING SYSTEM
----------------
All (tested on Windows and Solaris)

FULL JDK VERSION
----------------
JDK 5 and greater, including JDK 8
Note:  The ArrayStoreException begin with 5.0u6 (See CR 6322301 fix).

PROBLEM DESCRIPTION from LICENSEE
---------------------------------
A call to Class.getAnnotation() throws the following java.lang.ArrayStoreException when an annotation's Class is not present on the classpath. The following stack is from JDK8-b39:

Exception in thread "main" java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
        at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:677)
        at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:484)
        at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:308)
        at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:242)
        at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:88)
        at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:70)
        at java.lang.Class.initAnnotationsIfNecessary(Class.java:3093)
        at java.lang.Class.getAnnotation(Class.java:3052)
        at AnnotationTest.doTest(AnnotationTest.java:9)
        at AnnotationTest.main(AnnotationTest.java:5)

The API specification for java.lang.Class states that Class.getAnnotation() returns this element's annotation for the specified type if such an annotation is present, else null. ArrayStoreException is not a checked Exception so it doesn't have to be declared, but it effectively prevents the API from following the specification - either the annotation should be returned, or null.  Currently neither happens.

The application could catch the ArrayStoreException and handle it, but Licensee prefers it to be dealt with in the JDK's internal implementation.

TESTCASE AND REPRODUCTION INSTRUCTIONS
--------------------------------------
Attached

WORKAROUND
----------
Catch the undocumented ArrayStoreException and handle it.

Comments
Release team: Approved for deferral. I couldn't find where you wanted to defer this so I've moved it to 9. If that was incorrect then please update FixVersion
21-10-2013

One more comment: Annotation a = this.getClass().getAnnotation(Annotation.class); System.out.println("Annotation: " + a); Annotation.class is present in the path; its the class value member (Missing.class) that is removed from the test dir. So, I would expect that 'a' will get an Annotation object, however, when I try to use 'a' to get its members, here, Missing.class then an exception is fine.
18-10-2013

8-defer-SQE-OK - This is not a regression and not clearly a violation of the api spec. The "missing" class is not an annotation but a class with is the value of an annotation. This test, http://hg.openjdk.java.net/jdk8/tl/jdk/file/60e3cdbe8cdf/test/java/lang/annotation/Missing/MissingTest.java, has a tests case on line 122 which covers this situation.
17-10-2013

8-defer-request: The possible fix(es) will need more discussion, and there are compatibility concerns around them. It would be preferable to do behavioural change like this earlier in a major release so that there is more time to learn about possible consequence.
15-10-2013

You may be right. The reason to ignore the missing class is to be consistent with other cases where missing *annotation* classes are silently ignored. But yes, this case is different. It's not clear the current spec covers this case, so it should probably be enhanced as well.
18-09-2013

My (personal) proposal is to throw TypeNotPresentException for a.value(). While I see the merit in only stripping the not present elements from the array, I think that may lead to problems: the semantics of the array and its elements is unknown (depends on the annotation definition), so not silently ignoring some elements from the array can have unknown effects.
18-09-2013

What would you do if the test case used @Annotation({String.class, MissingClass.class}) There's clearly no way for a.value() to return an array that throws an exception when you try to access the second element. Is it better for a.value() to throw the exception, or for a.value() to return a Class[] containing only String.class?
17-09-2013

While it would be possible to modify the AnnotationParser.parseClassArray() to create an Object[] instead of Class[], and put the ExceptionProxy there, that does not seem to be helpful: the array created by AnnotationParser.parseClassArray() is then returned from the annotation Proxy as the annotation's value (in the attached example, the array created AnnotationParser.parseClassArray() would be returned for "Annotation a; a.value();" - but that must return a Class[], not Object[]). It may be more appropriate to replace the whole array with an ExceptionProxy, i.e. throwing a TypeNotPresentException from "a.value()".
17-09-2013

Just giving this a kick to see if we can get it evaluated and fixed.
06-05-2013

WORK AROUND Catch the undocumented ArrayStoreException and handle it.
13-07-2012