private Class<?> getTypeVarConcreteClass (Class[] generics, int typeVarNum, String typeVarName) { if (generics != null && generics.length > typeVarNum) { // If passed concrete classes are known explicitly, use this information return generics[typeVarNum]; } else { // Otherwise try to derive the information from the current GenericScope if (TRACE) trace("kryo", "Trying to use kryo.getGenericScope"); Generics scope = kryo.getGenericsScope(); if (scope != null) { return scope.getConcreteClass(typeVarName); } } return null; }
Class[] computeFieldGenerics (Type fieldGenericType, Field field, Class[] fieldClass) { Class[] fieldGenerics = null; if (fieldGenericType != null) { if (fieldGenericType instanceof TypeVariable && serializer.getGenericsScope() != null) { TypeVariable typeVar = (TypeVariable)fieldGenericType; // Obtain information about a concrete type of a given variable from the environment Class concreteClass = serializer.getGenericsScope().getConcreteClass(typeVar.getName()); if (concreteClass != null) { fieldClass[0] = concreteClass; fieldGenerics = new Class[] {fieldClass[0]}; if (TRACE) trace("kryo", "Determined concrete class of '" + field.getName() + "' to be " + fieldClass[0].getName()); } } else if (fieldGenericType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)fieldGenericType; // Get actual type arguments of the current field's type Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); // if(actualTypeArguments != null && generics != null) { if (actualTypeArguments != null) { fieldGenerics = new Class[actualTypeArguments.length]; for (int i = 0; i < actualTypeArguments.length; ++i) { Type t = actualTypeArguments[i]; if (t instanceof Class) fieldGenerics[i] = (Class)t; else if (t instanceof ParameterizedType) fieldGenerics[i] = (Class)((ParameterizedType)t).getRawType(); else if (t instanceof TypeVariable && serializer.getGenericsScope() != null) fieldGenerics[i] = serializer.getGenericsScope().getConcreteClass(((TypeVariable)t).getName()); else if (t instanceof WildcardType) fieldGenerics[i] = Object.class; else if (t instanceof GenericArrayType) { Type componentType = ((GenericArrayType)t).getGenericComponentType(); if (componentType instanceof Class) fieldGenerics[i] = Array.newInstance((Class)componentType, 0).getClass(); else if (componentType instanceof TypeVariable) { Generics scope = serializer.getGenericsScope(); if (scope != null) { Class clazz = scope.getConcreteClass(((TypeVariable)componentType).getName()); if (clazz != null) { fieldGenerics[i] = Array.newInstance(clazz, 0).getClass(); } } } } else fieldGenerics[i] = null; } if (TRACE && fieldGenerics != null) { trace("kryo", "Determined concrete class of parametrized '" + field.getName() + "' to be " + fieldGenericType + " where type parameters are " + Arrays.toString(fieldGenerics)); } } } else if (fieldGenericType instanceof GenericArrayType) { // TODO: store generics for arrays as well? GenericArrayType arrayType = (GenericArrayType)fieldGenericType; Type genericComponentType = arrayType.getGenericComponentType(); Class[] tmpFieldClass = new Class[] {fieldClass[0]}; fieldGenerics = computeFieldGenerics(genericComponentType, field, tmpFieldClass); // Kryo.getGenerics(fieldGenericType); if (TRACE && fieldGenerics != null) { trace("kryo", "Determined concrete class of a generic array '" + field.getName() + "' to be " + fieldGenericType + " where type parameters are " + Arrays.toString(fieldGenerics)); } else if (TRACE) trace("kryo", "Determined concrete class of '" + field.getName() + "' to be " + fieldGenericType); } } return fieldGenerics; }
public final Generics getGenericsScope () { return genericsScope; }
/** Called when the list of cached fields must be rebuilt. This is done any time settings are changed that affect which fields * will be used. It is called from the constructor for FieldSerializer, but not for subclasses. Subclasses must call this from * their constructor. */ protected void rebuildCachedFields () { if (TRACE && generics != null) trace("kryo", "generic type parameters are: " + Arrays.toString(generics)); if (type.isInterface()) { fields = new CachedField[0]; // No fields to serialize. return; } hasObjectFields = false; // For generic classes, generate a mapping from type variable names to the concrete types // This mapping is the same for the whole class. Generics genScope = buildGenericsScope(type, generics); genericsScope = genScope; // Push proper scopes at serializer construction time if (genericsScope != null) kryo.pushGenericsScope(type, genericsScope); // Collect all fields. List<Field> allFields = new ArrayList(); Class nextClass = type; while (nextClass != Object.class) { Field[] declaredFields = nextClass.getDeclaredFields(); if (declaredFields != null) { for (Field f : declaredFields) { if (Modifier.isStatic(f.getModifiers())) continue; allFields.add(f); } } nextClass = nextClass.getSuperclass(); } ObjectMap context = kryo.getContext(); IntArray useAsm = new IntArray(); // Sort fields by their offsets if (useMemRegions && !useAsmEnabled && unsafe() != null) { Field[] allFieldsArray = softFieldsByOffset(allFields); allFields = Arrays.asList(allFieldsArray); } // TODO: useAsm is modified as a side effect, this should be pulled out of buildValidFields List<Field> validFields = buildValidFields(false, allFields, context, useAsm); List<Field> validTransientFields = buildValidFields(true, allFields, context, useAsm); // Use ReflectASM for any public fields. if (useAsmEnabled && !Util.isAndroid && Modifier.isPublic(type.getModifiers()) && useAsm.indexOf(1) != -1) { try { access = FieldAccess.get(type); } catch (RuntimeException ignored) { } } List<CachedField> cachedFields = new ArrayList(validFields.size()); List<CachedField> cachedTransientFields = new ArrayList(validTransientFields.size()); createCachedFields(useAsm, validFields, cachedFields, 0); createCachedFields(useAsm, validTransientFields, cachedTransientFields, validFields.size()); Collections.sort(cachedFields, this); fields = cachedFields.toArray(new CachedField[cachedFields.size()]); Collections.sort(cachedTransientFields, this); transientFields = cachedTransientFields.toArray(new CachedField[cachedTransientFields.size()]); initializeCachedFields(); if (genericsScope != null) kryo.popGenericsScope(); }