/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package java.lang.reflect; import java.lang.annotation.Annotation; import org.jikesrvm.classloader.VM_Class; import org.jikesrvm.classloader.VM_Field; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.objectmodel.VM_ObjectModel; import org.jikesrvm.runtime.VM_Runtime; /** * Implementation of java.lang.reflect.Field for JikesRVM. * * By convention, order methods in the same order * as they appear in the method summary list of Sun's 1.4 Javadoc API. */ public final class Field extends AccessibleObject implements Member { final VM_Field field; // Prevent this class from being instantiated. @SuppressWarnings("unused") private Field() { field = null; } // For use by JikesRVMSupport Field(VM_Field f) { field = f; } public boolean equals(Object object) { if (object instanceof Field) { return field == ((Field)object).field; } else { return false; } } public Object get(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); VM_TypeReference type = field.getType(); if (type.isReferenceType()) { return field.getObjectValueUnchecked(object); } else if (type.isCharType()) { return field.getCharValueUnchecked(object); } else if (type.isDoubleType()) { return field.getDoubleValueUnchecked(object); } else if (type.isFloatType()) { return field.getFloatValueUnchecked(object); } else if (type.isLongType()) { return field.getLongValueUnchecked(object); } else if (type.isIntType()) { return field.getIntValueUnchecked(object); } else if (type.isShortType()) { return field.getShortValueUnchecked(object); } else if (type.isByteType()) { return field.getByteValueUnchecked(object); } else if (type.isBooleanType()) { return field.getBooleanValueUnchecked(object); } else { throw new InternalError("Huh? Field of unknown primitive type "+type); } } public boolean getBoolean(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getBooleanInternal(object); } public byte getByte(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getByteInternal(object); } public char getChar(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getCharInternal(object); } public Class<?> getDeclaringClass() { return field.getDeclaringClass().getClassForType(); } public double getDouble(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getDoubleInternal(object); } public float getFloat(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getFloatInternal(object); } public int getInt(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getIntInternal(object); } public long getLong(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getLongInternal(object); } public int getModifiers() { return field.getModifiers(); } public String getName() { return field.getName().toString(); } public short getShort(Object object) throws IllegalAccessException, IllegalArgumentException { checkReadAccess(object); return getShortInternal(object); } public Class<?> getType() { return field.getType().resolve(false).getClassForType(); } public int hashCode() { int code1 = getName().hashCode(); int code2 = field.getDeclaringClass().toString().hashCode(); return code1 ^ code2; } public boolean isSynthetic() { return field.isSynthetic(); } public boolean isEnumConstant() { return field.isEnumConstant(); } public void set(Object object, Object value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); VM_TypeReference type = field.getType(); if (type.isReferenceType()) { if (value != null) { VM_Type valueType = VM_ObjectModel.getObjectType(value); VM_Type fieldType; try { fieldType = type.resolve(false); } catch (NoClassDefFoundError e) { throw new IllegalArgumentException("field type mismatch"); } if (fieldType != valueType && !VM_Runtime.isAssignableWith(fieldType, valueType)) { throw new IllegalArgumentException("field type mismatch"); } } field.setObjectValueUnchecked(object, value); } else if (value instanceof Character) { setCharInternal(object, (Character) value); } else if (value instanceof Double) { setDoubleInternal(object, (Double) value); } else if (value instanceof Float) { setFloatInternal(object, (Float) value); } else if (value instanceof Long) { setLongInternal(object, (Long) value); } else if (value instanceof Integer) { setIntInternal(object, (Integer) value); } else if (value instanceof Short) { setShortInternal(object, (Short) value); } else if (value instanceof Byte) { setByteInternal(object, (Byte) value); } else if (value instanceof Boolean) { setBooleanInternal(object, (Boolean) value); } else { throw new IllegalArgumentException("field type mismatch"); } } public void setBoolean(Object object, boolean value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setBooleanInternal(object, value); } public void setByte(Object object, byte value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setByteInternal(object, value); } public void setChar(Object object, char value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setCharInternal(object, value); } public void setDouble(Object object, double value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setDoubleInternal(object, value); } public void setFloat(Object object, float value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setFloatInternal(object, value); } public void setInt(Object object, int value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setIntInternal(object, value); } public void setLong(Object object, long value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setLongInternal(object, value); } public void setShort(Object object, short value) throws IllegalAccessException, IllegalArgumentException { checkWriteAccess(object); setShortInternal(object, value); } public String toString() { StringBuilder sb = new StringBuilder(64); Modifier.toString(getModifiers(), sb).append(' '); sb.append(JikesRVMHelpers.getUserName(getType())).append(' '); sb.append(getDeclaringClass().getName()).append('.'); sb.append(getName()); return sb.toString(); } private void checkReadAccess(Object obj) throws IllegalAccessException, IllegalArgumentException, ExceptionInInitializerError { VM_Class declaringClass = field.getDeclaringClass(); if (!field.isStatic()) { if (obj == null) { throw new NullPointerException(); } VM_Type objType = VM_ObjectModel.getObjectType(obj); if (objType != declaringClass && !VM_Runtime.isAssignableWith(declaringClass, objType)) { throw new IllegalArgumentException(); } } if (!field.isPublic() && !isAccessible()) { VM_Class accessingClass = VM_Class.getClassFromStackFrame(2); JikesRVMSupport.checkAccess(field, accessingClass); } if (field.isStatic() && !declaringClass.isInitialized(false)) { try { VM_Runtime.initializeClassForDynamicLink(declaringClass); } catch (Throwable e) { ExceptionInInitializerError ex = new ExceptionInInitializerError(); ex.initCause(e); throw ex; } } } private void checkWriteAccess(Object obj) throws IllegalAccessException, IllegalArgumentException, ExceptionInInitializerError { VM_Class declaringClass = field.getDeclaringClass(); if (!field.isStatic()) { if (obj == null) { throw new NullPointerException(); } VM_Type objType = VM_ObjectModel.getObjectType(obj); if (objType != declaringClass && !VM_Runtime.isAssignableWith(declaringClass, objType)) { throw new IllegalArgumentException(); } } if (!field.isPublic() && !isAccessible()) { VM_Class accessingClass = VM_Class.getClassFromStackFrame(2); JikesRVMSupport.checkAccess(field, accessingClass); } if (field.isFinal()) throw new IllegalAccessException(); if (field.isStatic() && !declaringClass.isInitialized(false)) { try { VM_Runtime.initializeClassForDynamicLink(declaringClass); } catch (Throwable e) { ExceptionInInitializerError ex = new ExceptionInInitializerError(); ex.initCause(e); throw ex; } } } public boolean getBooleanInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (!type.isBooleanType()) throw new IllegalArgumentException("field type mismatch"); return field.getBooleanValueUnchecked(object); } private byte getByteInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (!type.isByteType()) throw new IllegalArgumentException("field type mismatch"); return field.getByteValueUnchecked(object); } private char getCharInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (!type.isCharType()) throw new IllegalArgumentException("field type mismatch"); return field.getCharValueUnchecked(object); } private double getDoubleInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isDoubleType()) { return field.getDoubleValueUnchecked(object); } else if (type.isFloatType()) { return (double)field.getFloatValueUnchecked(object); } else if (type.isLongType()) { return (double)field.getLongValueUnchecked(object); } else if (type.isIntType()) { return (double)field.getIntValueUnchecked(object); } else if (type.isShortType()) { return (double)field.getShortValueUnchecked(object); } else if (type.isCharType()) { return (double)field.getCharValueUnchecked(object); } else if (type.isByteType()) { return (double)field.getByteValueUnchecked(object); } else { throw new IllegalArgumentException("field type mismatch"); } } private float getFloatInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isFloatType()) { return field.getFloatValueUnchecked(object); } else if (type.isLongType()) { return (float)field.getLongValueUnchecked(object); } else if (type.isIntType()) { return (float)field.getIntValueUnchecked(object); } else if (type.isShortType()) { return (float)field.getShortValueUnchecked(object); } else if (type.isCharType()) { return (float)field.getCharValueUnchecked(object); } else if (type.isByteType()) { return (float)field.getByteValueUnchecked(object); } else { throw new IllegalArgumentException("field type mismatch"); } } private int getIntInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isIntType()) { return field.getIntValueUnchecked(object); } else if (type.isShortType()) { return (int)field.getShortValueUnchecked(object); } else if (type.isCharType()) { return (int)field.getCharValueUnchecked(object); } else if (type.isByteType()) { return (int)field.getByteValueUnchecked(object); } else { throw new IllegalArgumentException("field type mismatch"); } } private long getLongInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isLongType()) { return field.getLongValueUnchecked(object); } else if (type.isIntType()) { return (long)field.getIntValueUnchecked(object); } else if (type.isShortType()) { return (long)field.getShortValueUnchecked(object); } else if (type.isCharType()) { return (long)field.getCharValueUnchecked(object); } else if (type.isByteType()) { return (long)field.getByteValueUnchecked(object); } else { throw new IllegalArgumentException("field type mismatch"); } } private short getShortInternal(Object object) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isShortType()) { return field.getShortValueUnchecked(object); } else if (type.isByteType()) { return (short)field.getByteValueUnchecked(object); } else { throw new IllegalArgumentException("field type mismatch"); } } private void setBooleanInternal(Object object, boolean value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isBooleanType()) field.setBooleanValueUnchecked(object, value); else throw new IllegalArgumentException("field type mismatch"); } private void setByteInternal(Object object, byte value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isByteType()) field.setByteValueUnchecked(object, value); else if (type.isLongType()) field.setLongValueUnchecked(object, (long)value); else if (type.isIntType()) field.setIntValueUnchecked(object, (int)value); else if (type.isShortType()) field.setShortValueUnchecked(object, (short)value); else if (type.isCharType()) field.setCharValueUnchecked(object, (char)value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else if (type.isFloatType()) field.setFloatValueUnchecked(object, (float)value); else throw new IllegalArgumentException("field type mismatch"); } private void setCharInternal(Object object, char value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isCharType()) field.setCharValueUnchecked(object, value); else if (type.isLongType()) field.setLongValueUnchecked(object, (long)value); else if (type.isIntType()) field.setIntValueUnchecked(object, (int)value); else if (type.isShortType()) field.setShortValueUnchecked(object, (short)value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else if (type.isFloatType()) field.setFloatValueUnchecked(object, (float)value); else throw new IllegalArgumentException("field type mismatch"); } private void setDoubleInternal(Object object, double value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isDoubleType()) field.setDoubleValueUnchecked(object, value); else throw new IllegalArgumentException("field type mismatch"); } private void setFloatInternal(Object object, float value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isFloatType()) field.setFloatValueUnchecked(object, value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else throw new IllegalArgumentException("field type mismatch"); } private void setIntInternal(Object object, int value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isIntType()) field.setIntValueUnchecked(object, value); else if (type.isLongType()) field.setLongValueUnchecked(object, (long) value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else if (type.isFloatType()) field.setFloatValueUnchecked(object, (float)value); else throw new IllegalArgumentException("field type mismatch"); } private void setLongInternal(Object object, long value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isLongType()) field.setLongValueUnchecked(object, value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else if (type.isFloatType()) field.setFloatValueUnchecked(object, (float)value); else throw new IllegalArgumentException("field type mismatch"); } private void setShortInternal(Object object, short value) throws IllegalArgumentException { VM_TypeReference type = field.getType(); if (type.isShortType()) field.setShortValueUnchecked(object, value); else if (type.isLongType()) field.setLongValueUnchecked(object, (long)value); else if (type.isIntType()) field.setIntValueUnchecked(object, (int)value); else if (type.isDoubleType()) field.setDoubleValueUnchecked(object, (double)value); else if (type.isFloatType()) field.setFloatValueUnchecked(object, (float)value); else throw new IllegalArgumentException("field type mismatch"); } // AnnotatedElement interface public Annotation[] getDeclaredAnnotations() { return field.getDeclaredAnnotations(); } public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { return field.getAnnotation(annotationClass); } // Generics support public Type getGenericType() { VM_Atom signature = field.getSignature(); if (signature == null) { return getType(); } else { return JikesRVMHelpers.getFieldType(this, signature); } } public String toGenericString() { StringBuilder sb = new StringBuilder(64); Modifier.toString(getModifiers(), sb).append(' '); sb.append(getGenericType()).append(' '); sb.append(getDeclaringClass().getName()).append('.'); sb.append(getName()); return sb.toString(); } }