/* * Copyright 2013 Guidewire Software, Inc. */ package gw.lang.reflect; import gw.lang.reflect.gs.IGenericTypeVariable; import gw.lang.reflect.java.IJavaClassInfo; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import java.lang.reflect.Array; import java.util.HashSet; import java.util.Set; public class DefaultArrayType extends AbstractType implements IDefaultArrayType, IHasJavaClass { private IType _componentType; transient private ITypeLoader _typeLoader; transient private ITypeInfo _typeInfo; transient private Set _allTypesInHierarchy; transient private IDefaultArrayType _arrayIntrinsicType; transient private IJavaClassInfo _concreteClass; transient private boolean _bDiscarded; private String _name; public DefaultArrayType( IType componentType, IJavaClassInfo componentConcreteClass, ITypeLoader typeLoader ) { _componentType = componentType; _typeLoader = typeLoader; _concreteClass = componentConcreteClass == null ? null : componentConcreteClass.getArrayType(); _name = _componentType.getName() + "[]"; assert (componentType instanceof INonLoadableType) == (this instanceof INonLoadableType) : "The loadability of component type of a DefaultArrayType must agree with the loadability of this type. \n" + "If " + componentType.getClass().getName() + " is non loadable, its type must use DefaultNonLoadableArrayType as its array type."; } public final IType getComponentType() { return _componentType; } /** */ public final String getRelativeName() { return _componentType.getRelativeName() + "[]"; } /** */ public final boolean isArray() { return true; } /** */ public final Object readResolve() { return TypeSystem.getByFullName(getName()); } public final boolean isValid() { return true; } public int getModifiers() { return _componentType.getModifiers(); } public final boolean isAbstract() { return false; } /** */ public final String getName() { return _name; } public final String getDisplayName() { return getName(); } /** */ public final String getNamespace() { return _componentType.getNamespace(); } public final ITypeLoader getTypeLoader() { return _typeLoader; } public final IType getSupertype() { return null; } public final IType getEnclosingType() { return null; } public final IType getGenericType() { return null; } public final boolean isFinal() { return false; } public final boolean isInterface() { return false; } public boolean isEnum() { return false; } public final IType[] getInterfaces() { return EMPTY_TYPE_ARRAY; } /** */ public final boolean isParameterizedType() { return false; } /** */ public final boolean isGenericType() { return false; } /** */ public final IGenericTypeVariable[] getGenericTypeVariables() { return null; } /** */ public final IType[] getTypeParameters() { return null; } /** */ public final IType getParameterizedType( IType... ofType ) { throw new UnsupportedOperationException( getName() + " does not support parameterization." ); } @SuppressWarnings({"unchecked"}) public final Set getAllTypesInHierarchy() { if( _allTypesInHierarchy == null ) { Set allTypes = new HashSet(); allTypes.add( JavaTypes.OBJECT() ); for( IType type : _componentType.getAllTypesInHierarchy() ) { allTypes.add( type.getArrayType() ); } if( _concreteClass != null ) { // Set<? extends IType> allTypesInHierarchy = TypeSystem.get( _concreteClass.getComponentType() ).getAllTypesInHierarchy(); Set<? extends IType> allTypesInHierarchy = _componentType.getAllTypesInHierarchy(); for( IType type : allTypesInHierarchy ) { if( type instanceof IJavaType ) { allTypes.add( type.getArrayType() ); } } } _allTypesInHierarchy = allTypes; } return _allTypesInHierarchy; } public final boolean isPrimitive() { return false; } public final IDefaultArrayType getArrayType() { if( _arrayIntrinsicType == null ) { // Check, then synch if necessary, then check again to avoid a race synchronized( this ) { if( _arrayIntrinsicType == null ) { // Note: we do the first assignment, then the second, so that the assignment to the instance variable // doesn't happen prior to the constructor completing, as the initial assignment might happen // before the constructor is done @SuppressWarnings({"UnnecessaryLocalVariable"}) IDefaultArrayType arrayIntrinsicType = makeArrayType(); _arrayIntrinsicType = arrayIntrinsicType; } } } return _arrayIntrinsicType; } /** * Allows subclasses to return a more specific interfaces */ protected IDefaultArrayType makeArrayType() { return new DefaultArrayType( getThisRef(), getConcreteClass(), _typeLoader ).getThisRef(); } public Object makeArrayInstance( int iLength ) { return Array.newInstance(getConcreteClass().getBackingClass(), iLength); } public IJavaClassInfo getConcreteClass() { return _concreteClass; } /** */ public Object getArrayComponent( Object array, int iIndex ) throws IllegalArgumentException, ArrayIndexOutOfBoundsException { return Array.get(array, iIndex); } /** */ public void setArrayComponent( Object array, int iIndex, Object value ) throws IllegalArgumentException, ArrayIndexOutOfBoundsException { Array.set( array, iIndex, value ); } /** */ public int getArrayLength( Object array ) throws IllegalArgumentException { return Array.getLength( array ); } /** */ public boolean isAssignableFrom( IType type ) { return type.getAllTypesInHierarchy().contains( getThisRef() ) || (type.isArray() && type.getClass().isInstance( getThisRef() ) && this.getComponentType().isAssignableFrom( type.getComponentType() )); } public boolean isMutable() { return true; } public final ITypeInfo getTypeInfo() { if( _typeInfo == null ) { _typeInfo = new DefaultArrayTypeInfo( getThisRef() ); } return _typeInfo; } /** */ public final void unloadTypeInfo() { _typeInfo = null; if( _arrayIntrinsicType != null ) { _arrayIntrinsicType.unloadTypeInfo(); } } public String toString() { return getComponentType().toString() + "[]"; } public IDefaultArrayType getThisRef() { IType compType = this; do { compType = compType.getComponentType(); } while( compType.isArray() ); return compType instanceof INonLoadableType || compType instanceof IJavaType ? this : (IDefaultArrayType)TypeSystem.getOrCreateTypeReference( this ); } public boolean isDiscarded() { return _bDiscarded; } public void setDiscarded( boolean bDiscarded ) { _bDiscarded = bDiscarded; } public boolean isCompoundType() { return false; } public Set<IType> getCompoundTypeComponents() { return null; } @Override public Class getBackingClass() { return getConcreteClass().getBackingClass(); } }