JDK-6261502 : (reflect) Add the functionality to screen out the "inappropriate" modifier bits
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2005-04-26
  • Updated: 2017-05-16
  • Resolved: 2009-09-11
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 7
7 b72Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
U:\javaclasses>java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)

A DESCRIPTION OF THE PROBLEM :
  Method.getModifers() on a bridge method is returning an int with the
  Modifier.VOLATILE bit set.

  Yes this is the same fault as bug 5070593 which has been closed.
  This IS a bug, and it is easily fixed.

  Wish this to be re-evaluated. 

the spec for Method.getModifiers() says
"Returns the Java language modifiers for the method represented by this Method
object, as an integer. The Modifier class should be used to decode the modifiers. "

While it is true that volatile and bridge share a bit in the JVM acces_flag
field, "bridge" is not a "java language modifier" and so returning that bit on
is a bug. Similarly for varargs flag using transient bit.

Method.getModifiers() should mask out the Modifier.VOLATILE and
Modifier.TRANSIENT bits, because on methods, these do NOT represent "java
language modifiers", but have other overloaded uses. Method.isBridge() and
Method.isVarArgs() are available for testing what these bits actually mean when
applied to methods.

Masking the return result from Method.getModifiers() thus alleviates the
Modifier.toString() problem mentioned in the other fault and apparent in my
sample code below.

Constructor.getModifiers() should also mask these bits out.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile and run source code below

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Modifier.toString(Method.getModifiers()) should return "public"
ACTUAL -
Modifier.toString(Method.getModifiers()) returns "public volatile"

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.reflect.*;

/** our proxy generator generates a volatile proxy for URI.compareTo(). Why? */

class VolatileMethod {
    public static void main(String[] args) {
        Class<?> uri=java.net.URI.class;
        Method compareTo;
        try {
            compareTo = uri.getDeclaredMethod("compareTo",Object.class);

            System.out.format(
                "method %s in %s%nis Bridge: %b%nis synthetic: %b%nhas modifiers
%s%n",
                compareTo,
                uri,
                compareTo.isBridge(),
                compareTo.isSynthetic(),
                Modifier.toString(compareTo.getModifiers())
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
###@###.### 2005-04-26 15:59:12 GMT

Comments
PUBLIC COMMENTS The issue is these values are not "constant" in the sense of being guaraneed to not change in the future. It is possible, if unlikey, that additional valid modifiers will be added in JDK 7 or later. While it possible to have non-constant public static final fields, those idioms are brittle compared to using a method call.
24-09-2009

PUBLIC COMMENTS It seems a bit clumsy to me to use methods like interfaceModifiers() to describe constants. The argument that otherwise the current bit set will get compiled into user programs doesn't really hold water. There's no reason you couldn't define Modifier.CLASS_MODIFIERS like this: public class Modifier { ... public static final CLASS_MODIFIERS = nonConstant(ABSTRACT|FINAL|...); ... private static final int nonConstant(int n) {return n;} } Perhaps I'm missing something?
24-09-2009

SUGGESTED FIX # HG changeset patch # User darcy # Date 1251493860 25200 # Node ID e0f79982edd2361dbe6f8624578e4bf6f3e0df91 # Parent 4a5f2147f953ace169f02b47ea245bb17ca293e2 6261502: (reflect) Add the functionality to screen out the "inappropriate" modifier bits Reviewed-by: alanb --- a/src/share/classes/java/lang/reflect/Constructor.java Fri Aug 28 11:11:11 2009 -0700 +++ b/src/share/classes/java/lang/reflect/Constructor.java Fri Aug 28 14:11:00 2009 -0700 @@ -81,10 +81,6 @@ public final // of permissions); we speed up the check in the common case by // remembering the last Class for which the check succeeded. private volatile Class securityCheckCache; - - // Modifiers that can be applied to a constructor in source code - private static final int LANGUAGE_MODIFIERS = - Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; // Generics infrastructure // Accessor for factory @@ -359,7 +355,7 @@ public final public String toString() { try { StringBuffer sb = new StringBuffer(); - int mod = getModifiers() & LANGUAGE_MODIFIERS; + int mod = getModifiers() & Modifier.constructorModifiers(); if (mod != 0) { sb.append(Modifier.toString(mod) + " "); } @@ -423,7 +419,7 @@ public final public String toGenericString() { try { StringBuilder sb = new StringBuilder(); - int mod = getModifiers() & LANGUAGE_MODIFIERS; + int mod = getModifiers() & Modifier.constructorModifiers(); if (mod != 0) { sb.append(Modifier.toString(mod) + " "); } --- a/src/share/classes/java/lang/reflect/Method.java Fri Aug 28 11:11:11 2009 -0700 +++ b/src/share/classes/java/lang/reflect/Method.java Fri Aug 28 14:11:00 2009 -0700 @@ -88,12 +88,6 @@ public final private Class securityCheckCache; private Class securityCheckTargetClassCache; - // Modifiers that can be applied to a method in source code - private static final int LANGUAGE_MODIFIERS = - Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | - Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | - Modifier.SYNCHRONIZED | Modifier.NATIVE; - // Generics infrastructure private String getGenericSignature() {return signature;} @@ -408,12 +402,12 @@ public final * {@code public}, {@code protected} or {@code private} first, * and then other modifiers in the following order: * {@code abstract}, {@code static}, {@code final}, - * {@code synchronized}, {@code native}. + * {@code synchronized}, {@code native}, {@code strictfp}. */ public String toString() { try { StringBuffer sb = new StringBuffer(); - int mod = getModifiers() & LANGUAGE_MODIFIERS; + int mod = getModifiers() & Modifier.methodModifiers(); if (mod != 0) { sb.append(Modifier.toString(mod) + " "); } @@ -473,7 +467,7 @@ public final * {@code public}, {@code protected} or {@code private} first, * and then other modifiers in the following order: * {@code abstract}, {@code static}, {@code final}, - * {@code synchronized} {@code native}. + * {@code synchronized}, {@code native}, {@code strictfp}. * * @return a string describing this {@code Method}, * include type parameters @@ -483,7 +477,7 @@ public final public String toGenericString() { try { StringBuilder sb = new StringBuilder(); - int mod = getModifiers() & LANGUAGE_MODIFIERS; + int mod = getModifiers() & Modifier.methodModifiers(); if (mod != 0) { sb.append(Modifier.toString(mod) + " "); } --- a/src/share/classes/java/lang/reflect/Modifier.java Fri Aug 28 11:11:11 2009 -0700 +++ b/src/share/classes/java/lang/reflect/Modifier.java Fri Aug 28 14:11:00 2009 -0700 @@ -235,6 +235,11 @@ class Modifier { * possible validity of the combination of modifiers represented * by the input. * + * Note that to perform such checking for a known kind of entity, + * such as a constructor or method, first AND the argument of + * {@code toString} with the appropriate mask from a method like + * {@link #constructorModifiers} or {@link #methodModifiers}. + * * @param mod a set of modifiers * @return a string representation of the set of modifiers * represented by {@code mod} @@ -353,4 +358,108 @@ class Modifier { static boolean isSynthetic(int mod) { return (mod & SYNTHETIC) != 0; } + + /** + * See JLSv3 section 8.1.1. + */ + private static final int CLASS_MODIFIERS = + Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | + Modifier.STRICT; + + /** + * See JLSv3 section 9.1.1. + */ + private static final int INTERFACE_MODIFIERS = + Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.ABSTRACT | Modifier.STATIC | Modifier.STRICT; + + + /** + * See JLSv3 section 8.8.3. + */ + private static final int CONSTRUCTOR_MODIFIERS = + Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; + + /** + * See JLSv3 section 8.4.3. + */ + private static final int METHOD_MODIFIERS = + Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | + Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.STRICT; + + /** + * See JLSv3 section 8.3.1. + */ + private static final int FIELD_MODIFIERS = + Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | + Modifier.VOLATILE; + + /** + * Return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a class. + * @return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a class. + * + * @jls3 8.1.1 Class Modifiers + * @since 1.7 + */ + public static int classModifiers() { + return CLASS_MODIFIERS; + } + + /** + * Return an {@code int} value OR-ing together the source language + * modifiers that can be applied to an interface. + * @return an {@code int} value OR-ing together the source language + * modifiers that can be applied to an inteface. + * + * @jls3 9.1.1 Interface Modifiers + * @since 1.7 + */ + public static int interfaceModifiers() { + return INTERFACE_MODIFIERS; + } + + /** + * Return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a constructor. + * @return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a constructor. + * + * @jls3 8.8.3 Constructor Modifiers + * @since 1.7 + */ + public static int constructorModifiers() { + return CONSTRUCTOR_MODIFIERS; + } + + /** + * Return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a method. + * @return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a method. + * + * @jls3 8.4.3 Method Modifiers + * @since 1.7 + */ + public static int methodModifiers() { + return METHOD_MODIFIERS; + } + + + /** + * Return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a field. + * @return an {@code int} value OR-ing together the source language + * modifiers that can be applied to a field. + * + * @jls3 8.3.1 Field Modifiers + * @since 1.7 + */ + public static int fieldModifiers() { + return FIELD_MODIFIERS; + } }
28-08-2009

PUBLIC COMMENTS See http://hg.openjdk.java.net/jdk7/tl/jdk/rev/e0f79982edd2
28-08-2009

EVALUATION A fine idea.
19-08-2009

WORK AROUND mask these bits off myself everywhere I call Method.getModifiers() ###@###.### 2005-04-26 15:59:13 GMT
26-04-2005