8296743: Tighten Class.getModifiers spec for array classes
Reviewed-by: rriggs, mchung, heidinga
This commit is contained in:
parent
3a15e8483c
commit
6fd1442123
@ -1296,17 +1296,21 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* {@code abstract} and {@code interface}; they should be decoded
|
||||
* using the methods of class {@code Modifier}.
|
||||
*
|
||||
* <p> If the underlying class is an array class, then its
|
||||
* {@code public}, {@code private} and {@code protected}
|
||||
* modifiers are the same as those of its component type. If this
|
||||
* {@code Class} object represents a primitive type or void, its
|
||||
* {@code public} modifier is always {@code true}, and its
|
||||
* {@code protected} and {@code private} modifiers are always
|
||||
* {@code false}. If this {@code Class} object represents an array class, a
|
||||
* primitive type or void, then its {@code final} modifier is always
|
||||
* {@code true} and its interface modifier is always
|
||||
* {@code false}. The values of its other modifiers are not determined
|
||||
* by this specification.
|
||||
* <p> If the underlying class is an array class:
|
||||
* <ul>
|
||||
* <li> its {@code public}, {@code private} and {@code protected}
|
||||
* modifiers are the same as those of its component type
|
||||
* <li> its {@code abstract} and {@code final} modifiers are always
|
||||
* {@code true}
|
||||
* <li> its interface modifier is always {@code false}, even when
|
||||
* the component type is an interface
|
||||
* </ul>
|
||||
* If this {@code Class} object represents a primitive type or
|
||||
* void, its {@code public}, {@code abstract}, and {@code final}
|
||||
* modifiers are always {@code true}.
|
||||
* For {@code Class} objects representing void, primitive types, and
|
||||
* arrays, the values of other modifiers are {@code false} other
|
||||
* than as specified above.
|
||||
*
|
||||
* <p> The modifier encodings are defined in section {@jvms 4.1}
|
||||
* of <cite>The Java Virtual Machine Specification</cite>.
|
||||
@ -1320,6 +1324,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 1.1
|
||||
* @jls 8.1.1 Class Modifiers
|
||||
* @jls 9.1.1. Interface Modifiers
|
||||
* @jvms 4.1 The {@code ClassFile} Structure
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
public native int getModifiers();
|
||||
@ -1328,17 +1333,19 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* {@return an unmodifiable set of the {@linkplain AccessFlag access
|
||||
* flags} for this class, possibly empty}
|
||||
*
|
||||
* <p> If the underlying class is an array class, then its
|
||||
* {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
|
||||
* access flags are the same as those of its component type. If this
|
||||
* {@code Class} object represents a primitive type or void, the
|
||||
* {@code PUBLIC} access flag is present, and the
|
||||
* {@code PROTECTED} and {@code PRIVATE} access flags are always
|
||||
* absent. If this {@code Class} object represents an array class, a
|
||||
* primitive type or void, then the {@code FINAL} access flag is always
|
||||
* present and the interface access flag is always
|
||||
* absent. The values of its other access flags are not determined
|
||||
* by this specification.
|
||||
* <p> If the underlying class is an array class:
|
||||
* <ul>
|
||||
* <li> its {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
|
||||
* access flags are the same as those of its component type
|
||||
* <li> its {@code ABSTRACT} and {@code FINAL} flags are present
|
||||
* <li> its {@code INTERFACE} flag is absent, even when the
|
||||
* component type is an interface
|
||||
* </ul>
|
||||
* If this {@code Class} object represents a primitive type or
|
||||
* void, the flags are {@code PUBLIC}, {@code ABSTRACT}, and
|
||||
* {@code FINAL}.
|
||||
* For {@code Class} objects representing void, primitive types, and
|
||||
* arrays, access flags are absent other than as specified above.
|
||||
*
|
||||
* @see #getModifiers()
|
||||
* @jvms 4.1 The ClassFile Structure
|
||||
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8296743
|
||||
* @summary Verify array classes and primitives have expected modifiers
|
||||
*/
|
||||
@ExpectedModifiers(Modifier.PUBLIC | Modifier.FINAL | Modifier.ABSTRACT)
|
||||
public class TestPrimitiveAndArrayModifiers {
|
||||
|
||||
/*
|
||||
* Relevant excerpt of the Class.getModifiers() specification:
|
||||
* <p> If the underlying class is an array class:
|
||||
* <ul>
|
||||
* <li> its {@code public}, {@code private} and {@code protected}
|
||||
* modifiers are the same as those of its component type
|
||||
* <li> its {@code final} and {@code abstract} modifiers are always
|
||||
* {@code true}
|
||||
* <li> its interface modifier is always {@code false}, even when
|
||||
* the component type is an interface
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
testPrimitives();
|
||||
testArrays();
|
||||
}
|
||||
|
||||
private static void testArrays() {
|
||||
Class<?>[] testCases = {
|
||||
TestPrimitiveAndArrayModifiers.class,
|
||||
|
||||
PackagePrivateClass.class,
|
||||
ProtectedClass.class,
|
||||
PrivateClass.class,
|
||||
|
||||
PublicInterface.class,
|
||||
PackagePrivateInterface.class,
|
||||
ProtectedInterface.class,
|
||||
PrivateInterface.class,
|
||||
};
|
||||
|
||||
for(var testCase : testCases) {
|
||||
int expectedModifiers =
|
||||
testCase.getAnnotation(ExpectedModifiers.class).value();
|
||||
Class<?> arrayClass = testCase.arrayType();
|
||||
int actualModifiers = arrayClass.getModifiers();
|
||||
if (expectedModifiers != actualModifiers) {
|
||||
throw new RuntimeException("Expected " + Modifier.toString(expectedModifiers) +
|
||||
"on " + testCase.getCanonicalName() +
|
||||
", but got " + Modifier.toString(actualModifiers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT)
|
||||
class PackagePrivateClass {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT | Modifier.PROTECTED)
|
||||
protected class ProtectedClass {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT | Modifier.PRIVATE)
|
||||
private class PrivateClass {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT | Modifier.PUBLIC)
|
||||
public interface PublicInterface {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT)
|
||||
interface PackagePrivateInterface {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT | Modifier.PROTECTED)
|
||||
protected interface ProtectedInterface {}
|
||||
|
||||
@ExpectedModifiers(Modifier.FINAL | Modifier.ABSTRACT | Modifier.PRIVATE)
|
||||
private interface PrivateInterface {}
|
||||
|
||||
/*
|
||||
* Relevant excerpt of the Class.getModifiers() specification:
|
||||
*
|
||||
* If this {@code Class} object represents a primitive type or
|
||||
* void, its {@code public}, {@code abstract}, and {@code final}
|
||||
* modifiers are always {@code true}.
|
||||
*/
|
||||
private static void testPrimitives() {
|
||||
Class<?>[] testCases = {
|
||||
void.class,
|
||||
boolean.class,
|
||||
byte.class,
|
||||
short.class,
|
||||
char.class,
|
||||
int.class,
|
||||
float.class,
|
||||
long.class,
|
||||
double.class,
|
||||
};
|
||||
|
||||
for(var testCase : testCases) {
|
||||
int actualModifiers = testCase.getModifiers();
|
||||
if ((Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.FINAL) !=
|
||||
actualModifiers) {
|
||||
throw new RuntimeException("Bad modifiers " +
|
||||
Modifier.toString(actualModifiers) +
|
||||
" on primitive type " + testCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExpectedModifiers {
|
||||
int value() default 0;
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8266670 8291734
|
||||
* @bug 8266670 8291734 8296743
|
||||
* @summary Test expected AccessFlag's on classes.
|
||||
*/
|
||||
|
||||
@ -98,23 +98,14 @@ public final class ClassAccessFlagTest {
|
||||
void.class // same access flag rules
|
||||
};
|
||||
|
||||
var mustBePresent = Set.of(AccessFlag.PUBLIC, AccessFlag.FINAL);
|
||||
var mustBeAbsent = Set.of(AccessFlag.PRIVATE,
|
||||
AccessFlag.PROTECTED,
|
||||
AccessFlag.INTERFACE);
|
||||
var expected = Set.of(AccessFlag.PUBLIC,
|
||||
AccessFlag.FINAL,
|
||||
AccessFlag.ABSTRACT);
|
||||
|
||||
for(var primClass : primitives) {
|
||||
// PUBLIC must be present, PROTECTED and PRIVATE must be
|
||||
// absent.
|
||||
// FINAL must be present, INTERFACE must be absent.
|
||||
var accessFlags = primClass.accessFlags();
|
||||
if (!accessFlags.containsAll(mustBePresent)) {
|
||||
throw new RuntimeException("Missing mandatory flags on " +
|
||||
primClass);
|
||||
}
|
||||
|
||||
if (containsAny(accessFlags, mustBeAbsent)) {
|
||||
throw new RuntimeException("Unexpected flags present on " +
|
||||
if (!accessFlags.equals(expected)) {
|
||||
throw new RuntimeException("Unexpected flags on " +
|
||||
primClass);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user