From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/lang/Class.java | 1799 ++++++++++++++++++++++++++++++++ 1 file changed, 1799 insertions(+) create mode 100644 libjava/classpath/java/lang/Class.java (limited to 'libjava/classpath/java/lang/Class.java') diff --git a/libjava/classpath/java/lang/Class.java b/libjava/classpath/java/lang/Class.java new file mode 100644 index 000000000..1caee0147 --- /dev/null +++ b/libjava/classpath/java/lang/Class.java @@ -0,0 +1,1799 @@ +/* Class.java -- Representation of a Java class. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.classpath.VMStackWalker; +import gnu.java.lang.reflect.ClassSignatureParser; + +import java.io.InputStream; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.net.URL; +import java.security.AccessController; +import java.security.AllPermission; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; + + +/** + * A Class represents a Java type. There will never be multiple Class + * objects with identical names and ClassLoaders. Primitive types, array + * types, and void also have a Class object. + * + *

Arrays with identical type and number of dimensions share the same class. + * The array class ClassLoader is the same as the ClassLoader of the element + * type of the array (which can be null to indicate the bootstrap classloader). + * The name of an array class is [<signature format>;. + *

For example, + * String[]'s class is [Ljava.lang.String;. boolean, byte, + * short, char, int, long, float and double have the "type name" of + * Z,B,S,C,I,J,F,D for the purposes of array classes. If it's a + * multidimensioned array, the same principle applies: + * int[][][] == [[[I. + * + *

There is no public constructor - Class objects are obtained only through + * the virtual machine, as defined in ClassLoaders. + * + * @serialData Class objects serialize specially: + * TC_CLASS ClassDescriptor. For more serialization information, + * see {@link ObjectStreamClass}. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.0 + * @see ClassLoader + */ +public final class Class + implements Serializable, Type, AnnotatedElement, GenericDeclaration +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3206093459760846163L; + + /** + * Flag indicating a synthetic member. + * Note that this duplicates a constant in Modifier. + */ + private static final int SYNTHETIC = 0x1000; + + /** + * Flag indiciating an annotation class. + */ + private static final int ANNOTATION = 0x2000; + + /** + * Flag indicating an enum constant or an enum class. + * Note that this duplicates a constant in Modifier. + */ + private static final int ENUM = 0x4000; + + /** The class signers. */ + private Object[] signers = null; + /** The class protection domain. */ + private final transient ProtectionDomain pd; + + /* We use an inner class, so that Class doesn't have a static initializer */ + private static final class StaticData + { + static final ProtectionDomain unknownProtectionDomain; + + static + { + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + unknownProtectionDomain = new ProtectionDomain(null, permissions); + } + } + + final transient Object vmdata; + + /** newInstance() caches the default constructor */ + private transient Constructor constructor; + + /** + * Class is non-instantiable from Java code; only the VM can create + * instances of this class. + */ + Class(Object vmdata) + { + this(vmdata, null); + } + + Class(Object vmdata, ProtectionDomain pd) + { + this.vmdata = vmdata; + // If the VM didn't supply a protection domain and the class is an array, + // we "inherit" the protection domain from the component type class. This + // saves the VM from having to worry about protection domains for array + // classes. + if (pd == null && isArray()) + this.pd = getComponentType().pd; + else + this.pd = pd; + } + + /** + * Use the classloader of the current class to load, link, and initialize + * a class. This is equivalent to your code calling + * Class.forName(name, true, getClass().getClassLoader()). + * + * @param name the name of the class to find + * @return the Class object representing the class + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + */ + public static Class forName(String name) throws ClassNotFoundException + { + return VMClass.forName(name, true, VMStackWalker.getCallingClassLoader()); + } + + /** + * Use the specified classloader to load and link a class. If the loader + * is null, this uses the bootstrap class loader (provide the security + * check succeeds). Unfortunately, this method cannot be used to obtain + * the Class objects for primitive types or for void, you have to use + * the fields in the appropriate java.lang wrapper classes. + * + *

Calls classloader.loadclass(name, initialize). + * + * @param name the name of the class to find + * @param initialize whether or not to initialize the class at this time + * @param classloader the classloader to use to find the class; null means + * to use the bootstrap class loader + * + * @return the class object for the given class + * + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + * @throws SecurityException if the classloader argument + * is null and the caller does not have the + * RuntimePermission("getClassLoader") permission + * @see ClassLoader + * @since 1.2 + */ + public static Class forName(String name, boolean initialize, + ClassLoader classloader) + throws ClassNotFoundException + { + if (classloader == null) + { + // Check if we may access the bootstrap classloader + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + } + return (Class) VMClass.forName(name, initialize, classloader); + } + + /** + * Get all the public member classes and interfaces declared in this + * class or inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getClasses() + { + memberAccessCheck(Member.PUBLIC); + return internalGetClasses(); + } + + /** + * Like getClasses() but without the security checks. + */ + private Class[] internalGetClasses() + { + ArrayList list = new ArrayList(); + list.addAll(Arrays.asList(getDeclaredClasses(true))); + Class superClass = getSuperclass(); + if (superClass != null) + list.addAll(Arrays.asList(superClass.internalGetClasses())); + return list.toArray(new Class[list.size()]); + } + + /** + * Get the ClassLoader that loaded this class. If the class was loaded + * by the bootstrap classloader, this method will return null. + * If there is a security manager, and the caller's class loader is not + * an ancestor of the requested one, a security check of + * RuntimePermission("getClassLoader") + * must first succeed. Primitive types and void return null. + * + * @return the ClassLoader that loaded this class + * @throws SecurityException if the security check fails + * @see ClassLoader + * @see RuntimePermission + */ + public ClassLoader getClassLoader() + { + if (isPrimitive()) + return null; + + ClassLoader loader = VMClass.getClassLoader(this); + // Check if we may get the classloader + SecurityManager sm = SecurityManager.current; + if (loader != null && sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(loader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return loader; + } + + /** + * If this is an array, get the Class representing the type of array. + * Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and + * calling getComponentType on that would give "java.lang.String". If + * this is not an array, returns null. + * + * @return the array type of this class, or null + * @see Array + * @since 1.1 + */ + public Class getComponentType() + { + return VMClass.getComponentType (this); + } + + /** + * Get a public constructor declared in this class. If the constructor takes + * no argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getConstructors() + * @since 1.1 + */ + public Constructor getConstructor(Class... types) + throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + Constructor[] constructors = getDeclaredConstructors(true); + for (int i = 0; i < constructors.length; i++) + { + Constructor constructor = constructors[i]; + if (matchParameters(types, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } + + /** + * Get all the public constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with checkMemberAccess(this, Member.PUBLIC) + * as well as checkPackageAccess both having to succeed. + * + * @return all public constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getConstructors() + { + memberAccessCheck(Member.PUBLIC); + return getDeclaredConstructors(true); + } + + /** + * Get a constructor declared in this class. If the constructor takes no + * argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredConstructors() + * @since 1.1 + */ + public Constructor getDeclaredConstructor(Class... types) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + Constructor[] constructors = getDeclaredConstructors(false); + for (int i = 0; i < constructors.length; i++) + { + Constructor constructor = constructors[i]; + if (matchParameters(types, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } + + /** + * Get all the declared member classes and interfaces in this class, but + * not those inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getDeclaredClasses() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredClasses(false); + } + + Class[] getDeclaredClasses (boolean publicOnly) + { + return VMClass.getDeclaredClasses (this, publicOnly); + } + + /** + * Get all the declared constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with checkMemberAccess(this, Member.DECLARED) + * as well as checkPackageAccess both having to succeed. + * + * @return all constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getDeclaredConstructors() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredConstructors(false); + } + + Constructor[] getDeclaredConstructors (boolean publicOnly) + { + return VMClass.getDeclaredConstructors (this, publicOnly); + } + + /** + * Get a field declared in this class, where name is its simple name. The + * implicit length field of arrays is not available. A security check may + * be performed, with checkMemberAccess(this, Member.DECLARED) + * as well as checkPackageAccess both having to succeed. + * + * @param name the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredFields() + * @since 1.1 + */ + public Field getDeclaredField(String name) throws NoSuchFieldException + { + memberAccessCheck(Member.DECLARED); + Field[] fields = getDeclaredFields(false); + for (int i = 0; i < fields.length; i++) + { + if (fields[i].getName().equals(name)) + return fields[i]; + } + throw new NoSuchFieldException(); + } + + /** + * Get all the declared fields in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getDeclaredFields() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredFields(false); + } + + Field[] getDeclaredFields (boolean publicOnly) + { + return VMClass.getDeclaredFields (this, publicOnly); + } + + /** + * Get a method declared in this class, where name is its simple name. The + * implicit methods of Object are not available from arrays or interfaces. + * Constructors (named "<init>" in the class file) and class initializers + * (name "<clinit>") are not available. The Virtual Machine allows + * multiple methods with the same signature but differing return types; in + * such a case the most specific return types are favored, then the final + * choice is arbitrary. If the method takes no argument, an array of zero + * elements and null are equivalent for the types argument. A security + * check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredMethods() + * @since 1.1 + */ + public Method getDeclaredMethod(String methodName, Class... types) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + Method match = matchMethod(getDeclaredMethods(false), methodName, types); + if (match == null) + throw new NoSuchMethodException(methodName); + return match; + } + + /** + * Get all the declared methods in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does include the implicit methods of + * arrays and interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * checkMemberAccess(this, Member.DECLARED) as well as + * checkPackageAccess both having to succeed. + * + * @return all declared methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Method[] getDeclaredMethods() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredMethods(false); + } + + Method[] getDeclaredMethods (boolean publicOnly) + { + return VMClass.getDeclaredMethods (this, publicOnly); + } + + /** + * If this is a nested or inner class, return the class that declared it. + * If not, return null. + * + * @return the declaring class of this class + * @since 1.1 + */ + public Class getDeclaringClass() + { + return VMClass.getDeclaringClass (this); + } + + /** + * Get a public field declared or inherited in this class, where name is + * its simple name. If the class contains multiple accessible fields by + * that name, an arbitrary one is returned. The implicit length field of + * arrays is not available. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param fieldName the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getFields() + * @since 1.1 + */ + public Field getField(String fieldName) + throws NoSuchFieldException + { + memberAccessCheck(Member.PUBLIC); + Field field = internalGetField(fieldName); + if (field == null) + throw new NoSuchFieldException(fieldName); + return field; + } + + /** + * Get all the public fields declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getFields() + { + memberAccessCheck(Member.PUBLIC); + return internalGetFields(); + } + + /** + * Like getFields() but without the security checks. + */ + private Field[] internalGetFields() + { + LinkedHashSet set = new LinkedHashSet(); + set.addAll(Arrays.asList(getDeclaredFields(true))); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].internalGetFields())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.internalGetFields())); + return set.toArray(new Field[set.size()]); + } + + /** + * Returns the Package in which this class is defined + * Returns null when this information is not available from the + * classloader of this class. + * + * @return the package for this class, if it is available + * @since 1.2 + */ + public Package getPackage() + { + ClassLoader cl = getClassLoader(); + if (cl != null) + return cl.getPackage(getPackagePortion(getName())); + else + return VMClassLoader.getPackage(getPackagePortion(getName())); + } + + /** + * Get the interfaces this class directly implements, in the + * order that they were declared. This returns an empty array, not null, + * for Object, primitives, void, and classes or interfaces with no direct + * superinterface. Array types return Cloneable and Serializable. + * + * @return the interfaces this class directly implements + */ + public Class[] getInterfaces() + { + return VMClass.getInterfaces (this); + } + + private static final class MethodKey + { + private String name; + private Class[] params; + private Class returnType; + private int hash; + + MethodKey(Method m) + { + name = m.getName(); + params = m.getParameterTypes(); + returnType = m.getReturnType(); + hash = name.hashCode() ^ returnType.hashCode(); + for(int i = 0; i < params.length; i++) + { + hash ^= params[i].hashCode(); + } + } + + public boolean equals(Object o) + { + if (o instanceof MethodKey) + { + MethodKey m = (MethodKey) o; + if (m.name.equals(name) && m.params.length == params.length + && m.returnType == returnType) + { + for (int i = 0; i < params.length; i++) + { + if (m.params[i] != params[i]) + return false; + } + return true; + } + } + return false; + } + + public int hashCode() + { + return hash; + } + } + + /** + * Get a public method declared or inherited in this class, where name is + * its simple name. The implicit methods of Object are not available from + * interfaces. Constructors (named "<init>" in the class file) and class + * initializers (name "<clinit>") are not available. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types, and the class can inherit multiple methods of the same + * return type; in such a case the most specific return types are favored, + * then the final choice is arbitrary. If the method takes no argument, an + * array of zero elements and null are equivalent for the types argument. + * A security check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getMethods() + * @since 1.1 + */ + public Method getMethod(String methodName, Class... types) + throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + Method method = internalGetMethod(methodName, types); + if (method == null) + throw new NoSuchMethodException(methodName); + return method; + } + + /** + * Like getMethod(String,Class[]) but without the security + * checks and returns null instead of throwing NoSuchMethodException. + */ + private Method internalGetMethod(String methodName, Class[] args) + { + Method match = matchMethod(getDeclaredMethods(true), methodName, args); + if (match != null) + return match; + Class superClass = getSuperclass(); + if (superClass != null) + { + match = superClass.internalGetMethod(methodName, args); + if(match != null) + return match; + } + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + match = interfaces[i].internalGetMethod(methodName, args); + if (match != null) + return match; + } + return null; + } + + /** + * Find the best matching method in list according to + * the definition of ``best matching'' used by getMethod() + * + *

+ * Returns the method if any, otherwise null. + * + * @param list List of methods to search + * @param name Name of method + * @param args Method parameter types + * @see #getMethod(String, Class[]) + */ + private static Method matchMethod(Method[] list, String name, Class[] args) + { + Method match = null; + for (int i = 0; i < list.length; i++) + { + Method method = list[i]; + if (!method.getName().equals(name)) + continue; + if (!matchParameters(args, method.getParameterTypes())) + continue; + if (match == null + || match.getReturnType().isAssignableFrom(method.getReturnType())) + match = method; + } + return match; + } + + /** + * Check for an exact match between parameter type lists. + * Either list may be null to mean a list of + * length zero. + */ + private static boolean matchParameters(Class[] types1, Class[] types2) + { + if (types1 == null) + return types2 == null || types2.length == 0; + if (types2 == null) + return types1 == null || types1.length == 0; + if (types1.length != types2.length) + return false; + for (int i = 0; i < types1.length; i++) + { + if (types1[i] != types2[i]) + return false; + } + return true; + } + + /** + * Get all the public methods declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does not include the implicit + * methods of interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * checkMemberAccess(this, Member.PUBLIC) as well as + * checkPackageAccess both having to succeed. + * + * @return all public methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Method[] getMethods() + { + memberAccessCheck(Member.PUBLIC); + // NOTE the API docs claim that no methods are returned for arrays, + // but Sun's implementation *does* return the public methods of Object + // (as would be expected), so we follow their implementation instead + // of their documentation. + return internalGetMethods(); + } + + /** + * Like getMethods() but without the security checks. + */ + private Method[] internalGetMethods() + { + HashMap map = new HashMap(); + Method[] methods; + Class[] interfaces = getInterfaces(); + for(int i = 0; i < interfaces.length; i++) + { + methods = interfaces[i].internalGetMethods(); + for(int j = 0; j < methods.length; j++) + { + map.put(new MethodKey(methods[j]), methods[j]); + } + } + Class superClass = getSuperclass(); + if(superClass != null) + { + methods = superClass.internalGetMethods(); + for(int i = 0; i < methods.length; i++) + { + map.put(new MethodKey(methods[i]), methods[i]); + } + } + methods = getDeclaredMethods(true); + for(int i = 0; i < methods.length; i++) + { + map.put(new MethodKey(methods[i]), methods[i]); + } + return map.values().toArray(new Method[map.size()]); + } + + /** + * Get the modifiers of this class. These can be decoded using Modifier, + * and is limited to one of public, protected, or private, and any of + * final, static, abstract, or interface. An array class has the same + * public, protected, or private modifier as its component type, and is + * marked final but not an interface. Primitive types and void are marked + * public and final, but not an interface. + * + * @return the modifiers of this class + * @see Modifier + * @since 1.1 + */ + public int getModifiers() + { + int mod = VMClass.getModifiers (this, false); + return (mod & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.FINAL | Modifier.STATIC | Modifier.ABSTRACT | + Modifier.INTERFACE)); + } + + /** + * Get the name of this class, separated by dots for package separators. + * If the class represents a primitive type, or void, then the + * name of the type as it appears in the Java programming language + * is returned. For instance, Byte.TYPE.getName() + * returns "byte". + * + * Arrays are specially encoded as shown on this table. + *

+   * array type          [element type
+   *                     (note that the element type is encoded per
+   *                      this table)
+   * boolean             Z
+   * byte                B
+   * char                C
+   * short               S
+   * int                 I
+   * long                J
+   * float               F
+   * double              D
+   * void                V
+   * class or interface, alone: <dotted name>
+   * class or interface, as element type: L<dotted name>;
+   * 
+ * + * @return the name of this class + */ + public String getName() + { + return VMClass.getName (this); + } + + /** + * Get a resource URL using this class's package using the + * getClassLoader().getResource() method. If this class was loaded using + * the system classloader, ClassLoader.getSystemResource() is used instead. + * + *

If the name you supply is absolute (it starts with a /), + * then the leading / is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * .'s are replaced with /. + * + *

The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return the URL to the resource + * @throws NullPointerException if name is null + * @since 1.1 + */ + public URL getResource(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoader(); + if (loader == null) + return ClassLoader.getSystemResource(name); + return loader.getResource(name); + } + + /** + * Get a resource using this class's package using the + * getClassLoader().getResourceAsStream() method. If this class was loaded + * using the system classloader, ClassLoader.getSystemResource() is used + * instead. + * + *

If the name you supply is absolute (it starts with a /), + * then the leading / is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * .'s are replaced with /. + * + *

The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return an InputStream with the contents of the resource in it, or null + * @throws NullPointerException if name is null + * @since 1.1 + */ + public InputStream getResourceAsStream(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoader(); + if (loader == null) + return ClassLoader.getSystemResourceAsStream(name); + return loader.getResourceAsStream(name); + } + + private String resourcePath(String resourceName) + { + if (resourceName.length() > 0) + { + if (resourceName.charAt(0) != '/') + { + String pkg = getPackagePortion(getName()); + if (pkg.length() > 0) + resourceName = pkg.replace('.','/') + '/' + resourceName; + } + else + { + resourceName = resourceName.substring(1); + } + } + return resourceName; + } + + /** + * Get the signers of this class. This returns null if there are no signers, + * such as for primitive types or void. + * + * @return the signers of this class + * @since 1.1 + */ + public Object[] getSigners() + { + return signers == null ? null : (Object[]) signers.clone (); + } + + /** + * Set the signers of this class. + * + * @param signers the signers of this class + */ + void setSigners(Object[] signers) + { + this.signers = signers; + } + + /** + * Get the direct superclass of this class. If this is an interface, + * Object, a primitive type, or void, it will return null. If this is an + * array type, it will return Object. + * + * @return the direct superclass of this class + */ + public Class getSuperclass() + { + return VMClass.getSuperclass (this); + } + + /** + * Return whether this class is an array type. + * + * @return whether this class is an array type + * @since 1.1 + */ + public boolean isArray() + { + return VMClass.isArray (this); + } + + /** + * Discover whether an instance of the Class parameter would be an + * instance of this Class as well. Think of doing + * isInstance(c.newInstance()) or even + * c.newInstance() instanceof (this class). While this + * checks widening conversions for objects, it must be exact for primitive + * types. + * + * @param c the class to check + * @return whether an instance of c would be an instance of this class + * as well + * @throws NullPointerException if c is null + * @since 1.1 + */ + public boolean isAssignableFrom(Class c) + { + return VMClass.isAssignableFrom (this, c); + } + + /** + * Discover whether an Object is an instance of this Class. Think of it + * as almost like o instanceof (this class). + * + * @param o the Object to check + * @return whether o is an instance of this class + * @since 1.1 + */ + public boolean isInstance(Object o) + { + return VMClass.isInstance (this, o); + } + + /** + * Check whether this class is an interface or not. Array types are not + * interfaces. + * + * @return whether this class is an interface or not + */ + public boolean isInterface() + { + return VMClass.isInterface (this); + } + + /** + * Return whether this class is a primitive type. A primitive type class + * is a class representing a kind of "placeholder" for the various + * primitive types, or void. You can access the various primitive type + * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., + * or through boolean.class, int.class, etc. + * + * @return whether this class is a primitive type + * @see Boolean#TYPE + * @see Byte#TYPE + * @see Character#TYPE + * @see Short#TYPE + * @see Integer#TYPE + * @see Long#TYPE + * @see Float#TYPE + * @see Double#TYPE + * @see Void#TYPE + * @since 1.1 + */ + public boolean isPrimitive() + { + return VMClass.isPrimitive (this); + } + + /** + * Get a new instance of this class by calling the no-argument constructor. + * The class is initialized if it has not been already. A security check + * may be performed, with checkMemberAccess(this, Member.PUBLIC) + * as well as checkPackageAccess both having to succeed. + * + * @return a new instance of this class + * @throws InstantiationException if there is not a no-arg constructor + * for this class, including interfaces, abstract classes, arrays, + * primitive types, and void; or if an exception occurred during + * the constructor + * @throws IllegalAccessException if you are not allowed to access the + * no-arg constructor because of scoping reasons + * @throws SecurityException if the security check fails + * @throws ExceptionInInitializerError if class initialization caused by + * this call fails with an exception + */ + public T newInstance() + throws InstantiationException, IllegalAccessException + { + memberAccessCheck(Member.PUBLIC); + Constructor constructor; + synchronized(this) + { + constructor = this.constructor; + } + if (constructor == null) + { + Constructor[] constructors = getDeclaredConstructors(false); + for (int i = 0; i < constructors.length; i++) + { + if (constructors[i].getParameterTypes().length == 0) + { + constructor = constructors[i]; + break; + } + } + if (constructor == null) + throw new InstantiationException(getName()); + if (!Modifier.isPublic(constructor.getModifiers()) + || !Modifier.isPublic(VMClass.getModifiers(this, true))) + { + setAccessible(constructor); + } + synchronized(this) + { + if (this.constructor == null) + this.constructor = constructor; + } + } + int modifiers = constructor.getModifiers(); + if (!Modifier.isPublic(modifiers) + || !Modifier.isPublic(VMClass.getModifiers(this, true))) + { + Class caller = VMStackWalker.getCallingClass(); + if (caller != null && + caller != this && + (Modifier.isPrivate(modifiers) + || getClassLoader() != caller.getClassLoader() + || !getPackagePortion(getName()) + .equals(getPackagePortion(caller.getName())))) + throw new IllegalAccessException(getName() + + " has an inaccessible constructor"); + } + try + { + return constructor.newInstance(); + } + catch (InvocationTargetException e) + { + VMClass.throwException(e.getTargetException()); + throw (InternalError) new InternalError + ("VMClass.throwException returned").initCause(e); + } + } + + /** + * Returns the protection domain of this class. If the classloader did not + * record the protection domain when creating this class the unknown + * protection domain is returned which has a null code source + * and all permissions. A security check may be performed, with + * RuntimePermission("getProtectionDomain"). + * + * @return the protection domain + * @throws SecurityException if the security manager exists and the caller + * does not have RuntimePermission("getProtectionDomain"). + * @see RuntimePermission + * @since 1.2 + */ + public ProtectionDomain getProtectionDomain() + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkPermission(new RuntimePermission("getProtectionDomain")); + + return pd == null ? StaticData.unknownProtectionDomain : pd; + } + + /** + * Return the human-readable form of this Object. For an object, this + * is either "interface " or "class " followed by getName(), + * for primitive types and void it is just getName(). + * + * @return the human-readable form of this Object + */ + public String toString() + { + if (isPrimitive()) + return getName(); + return (isInterface() ? "interface " : "class ") + getName(); + } + + /** + * Returns the desired assertion status of this class, if it were to be + * initialized at this moment. The class assertion status, if set, is + * returned; the backup is the default package status; then if there is + * a class loader, that default is returned; and finally the system default + * is returned. This method seldom needs calling in user code, but exists + * for compilers to implement the assert statement. Note that there is no + * guarantee that the result of this method matches the class's actual + * assertion status. + * + * @return the desired assertion status + * @see ClassLoader#setClassAssertionStatus(String, boolean) + * @see ClassLoader#setPackageAssertionStatus(String, boolean) + * @see ClassLoader#setDefaultAssertionStatus(boolean) + * @since 1.4 + */ + public boolean desiredAssertionStatus() + { + ClassLoader c = getClassLoader(); + Object status; + if (c == null) + return VMClassLoader.defaultAssertionStatus(); + if (c.classAssertionStatus != null) + synchronized (c) + { + status = c.classAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + status = ClassLoader.StaticData. + systemClassAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + if (c.packageAssertionStatus != null) + synchronized (c) + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = c.packageAssertionStatus.get(null); + else + do + { + status = c.packageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = ClassLoader.StaticData. + systemPackageAssertionStatus.get(null); + else + do + { + status = ClassLoader.StaticData. + systemPackageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + return c.defaultAssertionStatus; + } + + /** + *

+ * Casts this class to represent a subclass of the specified class. + * This method is useful for `narrowing' the type of a class so that + * the class object, and instances of that class, can match the contract + * of a more restrictive method. For example, if this class has the + * static type of Class<Object>, and a dynamic type of + * Class<Rectangle>, then, assuming Shape is + * a superclass of Rectangle, this method can be used on + * this class with the parameter, Class<Shape>, to retain + * the same instance but with the type + * Class<? extends Shape>. + *

+ *

+ * If this class can be converted to an instance which is parameterised + * over a subtype of the supplied type, U, then this method + * returns an appropriately cast reference to this object. Otherwise, + * a ClassCastException is thrown. + *

+ * + * @param klass the class object, the parameterized type (U) of + * which should be a superclass of the parameterized type of + * this instance. + * @return a reference to this object, appropriately cast. + * @throws ClassCastException if this class can not be converted to one + * which represents a subclass of the specified + * type, U. + * @since 1.5 + */ + public Class asSubclass(Class klass) + { + if (! klass.isAssignableFrom(this)) + throw new ClassCastException(); + return (Class) this; + } + + /** + * Returns the specified object, cast to this Class' type. + * + * @param obj the object to cast + * @throws ClassCastException if obj is not an instance of this class + * @since 1.5 + */ + public T cast(Object obj) + { + if (obj != null && ! isInstance(obj)) + throw new ClassCastException(); + return (T) obj; + } + + /** + * Like getField(String) but without the security checks and + * returns null instead of throwing NoSuchFieldException. + */ + private Field internalGetField(String name) + { + Field[] fields = getDeclaredFields(true); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if (field.getName().equals(name)) + return field; + } + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + Field field = interfaces[i].internalGetField(name); + if(field != null) + return field; + } + Class superClass = getSuperclass(); + if (superClass != null) + return superClass.internalGetField(name); + return null; + } + + /** + * Strip the last portion of the name (after the last dot). + * + * @param name the name to get package of + * @return the package name, or "" if no package + */ + private static String getPackagePortion(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return ""; + return name.substring(0, lastInd); + } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = SecurityManager.current; + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } + + /** + * Returns the enumeration constants of this class, or + * null if this class is not an Enum. + * + * @return an array of Enum constants + * associated with this class, or null if this + * class is not an enum. + * @since 1.5 + */ + public T[] getEnumConstants() + { + if (isEnum()) + { + try + { + Method m = getMethod("values"); + setAccessible(m); + return (T[]) m.invoke(null); + } + catch (NoSuchMethodException exception) + { + throw new Error("Enum lacks values() method"); + } + catch (IllegalAccessException exception) + { + throw new Error("Unable to access Enum class"); + } + catch (InvocationTargetException exception) + { + throw new + RuntimeException("The values method threw an exception", + exception); + } + } + else + { + return null; + } + } + + /** + * Returns true if this class is an Enum. + * + * @return true if this is an enumeration class. + * @since 1.5 + */ + public boolean isEnum() + { + int mod = VMClass.getModifiers (this, true); + return (mod & ENUM) != 0; + } + + /** + * Returns true if this class is a synthetic class, generated by + * the compiler. + * + * @return true if this is a synthetic class. + * @since 1.5 + */ + public boolean isSynthetic() + { + int mod = VMClass.getModifiers (this, true); + return (mod & SYNTHETIC) != 0; + } + + /** + * Returns true if this class is an Annotation. + * + * @return true if this is an annotation class. + * @since 1.5 + */ + public boolean isAnnotation() + { + int mod = VMClass.getModifiers (this, true); + return (mod & ANNOTATION) != 0; + } + + /** + * Returns the simple name for this class, as used in the source + * code. For normal classes, this is the content returned by + * getName() which follows the last ".". Anonymous + * classes have no name, and so the result of calling this method is + * "". The simple name of an array consists of the simple name of + * its component type, followed by "[]". Thus, an array with the + * component type of an anonymous class has a simple name of simply + * "[]". + * + * @return the simple name for this class. + * @since 1.5 + */ + public String getSimpleName() + { + return VMClass.getSimpleName(this); + } + + /** + * Returns this class' annotation for the specified annotation type, + * or null if no such annotation exists. + * + * @param annotationClass the type of annotation to look for. + * @return this class' annotation for the specified type, or + * null if no such annotation exists. + * @since 1.5 + */ + public A getAnnotation(Class annotationClass) + { + A foundAnnotation = null; + Annotation[] annotations = getAnnotations(); + for (Annotation annotation : annotations) + if (annotation.annotationType() == annotationClass) + foundAnnotation = (A) annotation; + return foundAnnotation; + } + + /** + * Returns all annotations associated with this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return this class' annotations. + * @since 1.5 + */ + public Annotation[] getAnnotations() + { + HashMap map = new HashMap(); + for (Annotation a : getDeclaredAnnotations()) + map.put((Class) a.annotationType(), a); + for (Class s = getSuperclass(); + s != null; + s = s.getSuperclass()) + { + for (Annotation a : s.getDeclaredAnnotations()) + { + Class k = (Class) a.annotationType(); + if (! map.containsKey(k) && k.isAnnotationPresent(Inherited.class)) + map.put(k, a); + } + } + Collection v = map.values(); + return v.toArray(new Annotation[v.size()]); + } + + /** + *

+ * Returns the canonical name of this class, as defined by section + * 6.7 of the Java language specification. Each package, top-level class, + * top-level interface and primitive type has a canonical name. A member + * class has a canonical name, if its parent class has one. Likewise, + * an array type has a canonical name, if its component type does. + * Local or anonymous classes do not have canonical names. + *

+ *

+ * The canonical name for top-level classes, top-level interfaces and + * primitive types is always the same as the fully-qualified name. + * For array types, the canonical name is the canonical name of its + * component type with `[]' appended. + *

+ *

+ * The canonical name of a member class always refers to the place where + * the class was defined, and is composed of the canonical name of the + * defining class and the simple name of the member class, joined by `.'. + * For example, if a Person class has an inner class, + * M, then both its fully-qualified name and canonical name + * is Person.M. A subclass, Staff, of + * Person refers to the same inner class by the fully-qualified + * name of Staff.M, but its canonical name is still + * Person.M. + *

+ *

+ * Where no canonical name is present, null is returned. + *

+ * + * @return the canonical name of the class, or null if the + * class doesn't have a canonical name. + * @since 1.5 + */ + public String getCanonicalName() + { + return VMClass.getCanonicalName(this); + } + + /** + * Returns all annotations directly defined by this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return the annotations directly defined by this class. + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() + { + return VMClass.getDeclaredAnnotations(this); + } + + /** + * Returns the class which immediately encloses this class. If this class + * is a top-level class, this method returns null. + * + * @return the immediate enclosing class, or null if this is + * a top-level class. + * @since 1.5 + */ + public Class getEnclosingClass() + { + return VMClass.getEnclosingClass(this); + } + + /** + * Returns the constructor which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then null is returned. + * + * @return the immediate enclosing constructor if this class is + * declared within a constructor. Otherwise, null + * is returned. + * @since 1.5 + */ + public Constructor getEnclosingConstructor() + { + return VMClass.getEnclosingConstructor(this); + } + + /** + * Returns the method which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then null is returned. + * + * @return the immediate enclosing method if this class is + * declared within a method. Otherwise, null + * is returned. + * @since 1.5 + */ + public Method getEnclosingMethod() + { + return VMClass.getEnclosingMethod(this); + } + + /** + *

+ * Returns an array of Type objects which represent the + * interfaces directly implemented by this class or extended by this + * interface. + *

+ *

+ * If one of the superinterfaces is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the ParameterizedType + * interface, and only if an instance has not already been created. + *

+ *

+ * The order of the interfaces in the array matches the order in which + * the interfaces are declared. For classes which represent an array, + * an array of two interfaces, Cloneable and + * Serializable, is always returned, with the objects in + * that order. A class representing a primitive type or void always + * returns an array of zero size. + *

+ * + * @return an array of interfaces implemented or extended by this class. + * @throws GenericSignatureFormatError if the generic signature of one + * of the interfaces does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if any of the superinterfaces refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if any of the interfaces + * refer to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type[] getGenericInterfaces() + { + if (isPrimitive()) + return new Type[0]; + + String sig = VMClass.getClassSignature(this); + if (sig == null) + return getInterfaces(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getInterfaceTypes(); + } + + /** + *

+ * Returns a Type object representing the direct superclass, + * whether class, interface, primitive type or void, of this class. + * If this class is an array class, then a class instance representing + * the Object class is returned. If this class is primitive, + * an interface, or a representation of either the Object + * class or void, then null is returned. + *

+ *

+ * If the superclass is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the ParameterizedType + * interface, and only if an instance has not already been created. + *

+ * + * @return the superclass of this class. + * @throws GenericSignatureFormatError if the generic signature of the + * class does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if the superclass refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if the superclass + * refers to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type getGenericSuperclass() + { + if (isArray()) + return Object.class; + + if (isPrimitive() || isInterface() || this == Object.class) + return null; + + String sig = VMClass.getClassSignature(this); + if (sig == null) + return getSuperclass(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getSuperclassType(); + } + + /** + * Returns an array of TypeVariable objects that represents + * the type variables declared by this class, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public TypeVariable>[] getTypeParameters() + { + String sig = VMClass.getClassSignature(this); + if (sig == null) + return (TypeVariable>[])new TypeVariable[0]; + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Returns true if an annotation for the specified type is associated + * with this class. This is primarily a short-hand for using marker + * annotations. + * + * @param annotationClass the type of annotation to look for. + * @return true if an annotation exists for the specified type. + * @since 1.5 + */ + public boolean isAnnotationPresent(Class + annotationClass) + { + return getAnnotation(annotationClass) != null; + } + + /** + * Returns true if this object represents an anonymous class. + * + * @return true if this object represents an anonymous class. + * @since 1.5 + */ + public boolean isAnonymousClass() + { + return VMClass.isAnonymousClass(this); + } + + /** + * Returns true if this object represents an local class. + * + * @return true if this object represents an local class. + * @since 1.5 + */ + public boolean isLocalClass() + { + return VMClass.isLocalClass(this); + } + + /** + * Returns true if this object represents an member class. + * + * @return true if this object represents an member class. + * @since 1.5 + */ + public boolean isMemberClass() + { + return VMClass.isMemberClass(this); + } + + /** + * Utility method for use by classes in this package. + */ + static void setAccessible(final AccessibleObject obj) + { + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + obj.setAccessible(true); + return null; + } + }); + } +} -- cgit v1.2.3