/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.lang.reflect;
import gw.lang.reflect.java.IJavaClassInfo;
import gw.lang.reflect.java.IJavaType;
import gw.lang.reflect.java.JavaTypes;
import gw.lang.reflect.gs.IGenericTypeVariable;
import gw.lang.reflect.module.IModule;
import gw.util.concurrent.LockingLazyVar;
import java.io.ObjectStreamException;
import java.lang.reflect.Array;
import java.util.HashSet;
import java.util.Set;
public abstract class TypeBase extends AbstractType implements IType
{
private static final IType[] EMPTY_INTRINSIC_TYPES_ARRAY = new IType[0];
private static final IGenericTypeVariable[] EMPTY_TYPE_VARIABLES_ARRAY = new IGenericTypeVariable[0];
private transient final LockingLazyVar<Set<? extends IType>> _allTypesInHierarchyCache;
private transient final LockingLazyVar<IType> _arrayTypeCache;
protected transient final IJavaClassInfo _arrayComponentClass;
private transient boolean _bDiscarded;
protected TypeBase(IJavaClassInfo arrayComponentClass) {
_arrayComponentClass = arrayComponentClass;
_allTypesInHierarchyCache = new LockingLazyVar<Set<? extends IType>>() {
protected Set<? extends IType> init() {
return loadAllTypesInHierarchy();
}
};
_arrayTypeCache = new LockingLazyVar<IType>() {
protected IType init() {
IType arrayType = makeArrayType();
return TypeSystem.getOrCreateTypeReference(arrayType);
}
};
}
protected TypeBase(Class<?> arrayComponentClass) {
this(TypeSystem.getJavaClassInfo(arrayComponentClass));
}
protected TypeBase() {
this(Object.class);
}
protected IType makeArrayType() {
return new DefaultArrayType(TypeSystem.getOrCreateTypeReference(TypeBase.this), getArrayComponentClass(), getTypeLoader());
}
public IType getEnclosingType()
{
return null;
}
public IType getGenericType()
{
return null;
}
public boolean isFinal()
{
return false;
}
public boolean isInterface()
{
return false;
}
public boolean isEnum()
{
return false;
}
public boolean isParameterizedType()
{
return false;
}
public boolean isGenericType()
{
return false;
}
public IGenericTypeVariable[] getGenericTypeVariables()
{
return EMPTY_TYPE_VARIABLES_ARRAY;
}
public IType getParameterizedType( IType... ofType )
{
return null;
}
public IType[] getTypeParameters()
{
return EMPTY_INTRINSIC_TYPES_ARRAY;
}
public boolean isArray()
{
return false;
}
public boolean isPrimitive()
{
return false;
}
public Object getArrayComponent( Object array, int iIndex ) throws IllegalArgumentException, ArrayIndexOutOfBoundsException
{
return ((Object[]) array)[iIndex];
}
public void setArrayComponent( Object array, int iIndex, Object value ) throws IllegalArgumentException, ArrayIndexOutOfBoundsException
{
// Why does IntelliJ warn here?
//noinspection RedundantCast
((Object[]) array)[iIndex] = value;
}
public int getArrayLength( Object array ) throws IllegalArgumentException
{
return ((Object[]) array).length;
}
public IType getComponentType()
{
return null;
}
public boolean isMutable()
{
return true;
}
public Object readResolve() throws ObjectStreamException
{
return TypeSystem.getByFullName( getName() );
}
public boolean isValid()
{
return true;
}
public int getModifiers()
{
return Modifier.PUBLIC;
}
public boolean isAbstract()
{
return Modifier.isAbstract( getModifiers() );
}
public String getDisplayName()
{
return getName();
}
public String toString()
{
return getName();
}
public Set<? extends IType> getAllTypesInHierarchy() {
return _allTypesInHierarchyCache.get();
}
protected Set<? extends IType> loadAllTypesInHierarchy() {
Set<IType> allTypes;
if( isArray() )
{
allTypes = getArrayVersionsOfEachType( getComponentType().getAllTypesInHierarchy() );
}
else
{
allTypes = getAllClassesInClassHierarchyAsIntrinsicTypes( TypeSystem.getOrCreateTypeReference( this ) );
}
return allTypes;
}
protected static Set<IType> getAllClassesInClassHierarchyAsIntrinsicTypes( IType type )
{
HashSet<IType> typeSet = new HashSet<IType>();
addAllClassesInClassHierarchy( type, typeSet );
return typeSet;
}
private static void addAllClassesInClassHierarchy(IType type, Set<IType> set) {
if (!set.add(type)) {
return;
}
for (IType iface : type.getInterfaces()) {
addAllClassesInClassHierarchy(iface, set);
}
if (type.getSupertype() != null) {
addAllClassesInClassHierarchy(type.getSupertype(), set);
}
if (type.isParameterizedType()) {
addAllClassesInClassHierarchy(type.getGenericType(), set);
}
if (type.isGenericType() || !type.isParameterizedType()) {
addAllClassesInClassHierarchy(TypeSystem.getDefaultParameterizedType( type ), set);
}
}
protected Set<IType> getArrayVersionsOfEachType( Set<? extends IType> componentTypes )
{
Set<IType> allTypes = new HashSet<IType>( 1 + componentTypes.size() );
allTypes.add( JavaTypes.OBJECT() );
for( IType componentType : componentTypes )
{
allTypes.add( componentType.getArrayType() );
}
return allTypes;
}
public boolean isAssignableFrom(IType type) {
//noinspection SuspiciousMethodCalls
return type.getAllTypesInHierarchy().contains( TypeSystem.getOrCreateTypeReference( this ) );
}
public IType getArrayType() {
return _arrayTypeCache.get();
}
public Object makeArrayInstance(int iLength) {
return Array.newInstance(getArrayComponentClass().getBackingClass(), iLength);
}
protected IJavaClassInfo getArrayComponentClass() {
return _arrayComponentClass;
}
public void unloadTypeInfo() {
_allTypesInHierarchyCache.clear();
if (_arrayTypeCache.isLoaded()) {
_arrayTypeCache.get().unloadTypeInfo();
}
}
public boolean isDiscarded()
{
return _bDiscarded;
}
public void setDiscarded( boolean bDiscarded )
{
_bDiscarded = bDiscarded;
}
public boolean isCompoundType() {
return false;
}
public Set<IType> getCompoundTypeComponents() {
return null;
}
public IJavaType loadJavaType(String fullyQualifiedName) {
IModule module = getTypeLoader().getModule();
for (IModule m : module.getModuleTraversalList()) {
if (m != module) {
IDefaultTypeLoader typeLoader = m.getTypeLoaders(IDefaultTypeLoader.class).get(0);
IType type = typeLoader.getType(fullyQualifiedName);
if (type != null) {
return (IJavaType) type;
}
}
}
return null;
}
}