From 3078279ab17852f71ff5dfeabdb0d85834a2b7a2 Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 25 Mar 2019 15:50:38 +0100 Subject: [PATCH] Added external dependencies as appropriate --- src/dorkbox/util/generics/ClassHelper.java | 2 + .../util/generics/DefaultMethodHelper.java | 30 - src/dorkbox/util/generics/TypeResolver.java | 612 ------------------ .../serialization/ArraysAsListSerializer.java | 125 ---- .../FieldAnnotationAwareSerializer.java | 216 ------- .../util/serialization/FileSerializer.java | 2 +- .../UnmodifiableCollectionsSerializer.java | 205 ------ 7 files changed, 3 insertions(+), 1189 deletions(-) delete mode 100644 src/dorkbox/util/generics/DefaultMethodHelper.java delete mode 100644 src/dorkbox/util/generics/TypeResolver.java delete mode 100644 src/dorkbox/util/serialization/ArraysAsListSerializer.java delete mode 100644 src/dorkbox/util/serialization/FieldAnnotationAwareSerializer.java delete mode 100644 src/dorkbox/util/serialization/UnmodifiableCollectionsSerializer.java diff --git a/src/dorkbox/util/generics/ClassHelper.java b/src/dorkbox/util/generics/ClassHelper.java index dae90b8..ff1e12b 100644 --- a/src/dorkbox/util/generics/ClassHelper.java +++ b/src/dorkbox/util/generics/ClassHelper.java @@ -17,6 +17,8 @@ package dorkbox.util.generics; import java.lang.reflect.Type; +import net.jodah.typetools.TypeResolver; + public final class ClassHelper { diff --git a/src/dorkbox/util/generics/DefaultMethodHelper.java b/src/dorkbox/util/generics/DefaultMethodHelper.java deleted file mode 100644 index e180c9d..0000000 --- a/src/dorkbox/util/generics/DefaultMethodHelper.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 dorkbox, llc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.util.generics; - -import java.lang.reflect.Method; - -/** - * This class must be compiled for java 8+, and is needed by the TypeResolver in some situations - */ -public -class DefaultMethodHelper { - @SuppressWarnings("Since15") - static - boolean isDefaultMethod(Method m) { - return m.isDefault(); - } -} diff --git a/src/dorkbox/util/generics/TypeResolver.java b/src/dorkbox/util/generics/TypeResolver.java deleted file mode 100644 index 28cb339..0000000 --- a/src/dorkbox/util/generics/TypeResolver.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright 2018 dorkbox, llc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.util.generics; - -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.security.AccessController; -import java.security.PrivilegedExceptionAction; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.WeakHashMap; - -import dorkbox.util.OS; -import sun.misc.Unsafe; - -/** - * Enhanced type resolution utilities. - * - * From: https://github.com/jhalterman/typetools - * @author Jonathan Halterman - */ -@SuppressWarnings("restriction") -public final -class TypeResolver { - /** - * Cache of type variable/argument pairs - */ - private static final Map, Reference, Type>>> TYPE_VARIABLE_CACHE = Collections.synchronizedMap(new WeakHashMap, Reference, Type>>>()); - - private static volatile boolean CACHE_ENABLED = true; - private static boolean RESOLVES_LAMBDAS; - - private static Method GET_CONSTANT_POOL; - private static Method GET_CONSTANT_POOL_SIZE; - private static Method GET_CONSTANT_POOL_METHOD_AT; - - private static final Map OBJECT_METHODS = new HashMap(); - private static final Map, Class> PRIMITIVE_WRAPPERS; - - static { - try { - Unsafe unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public - Unsafe run() throws Exception { - final Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - - return (Unsafe) f.get(null); - } - }); - - GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool"); - String constantPoolName = OS.javaVersion < 9 ? "sun.reflect.ConstantPool" : "jdk.internal.reflect.ConstantPool"; - Class constantPoolClass = Class.forName(constantPoolName); - GET_CONSTANT_POOL_SIZE = constantPoolClass.getDeclaredMethod("getSize"); - GET_CONSTANT_POOL_METHOD_AT = constantPoolClass.getDeclaredMethod("getMethodAt", int.class); - - // setting the methods as accessible - Field overrideField = AccessibleObject.class.getDeclaredField("override"); - long overrideFieldOffset = unsafe.objectFieldOffset(overrideField); - unsafe.putBoolean(GET_CONSTANT_POOL, overrideFieldOffset, true); - unsafe.putBoolean(GET_CONSTANT_POOL_SIZE, overrideFieldOffset, true); - unsafe.putBoolean(GET_CONSTANT_POOL_METHOD_AT, overrideFieldOffset, true); - - // additional checks - make sure we get a result when invoking the Class::getConstantPool and - // ConstantPool::getSize on a class - Object constantPool = GET_CONSTANT_POOL.invoke(Object.class); - GET_CONSTANT_POOL_SIZE.invoke(constantPool); - - for (Method method : Object.class.getDeclaredMethods()) { - OBJECT_METHODS.put(method.getName(), method); - } - - RESOLVES_LAMBDAS = true; - } catch (Exception ignore) { - } - - Map, Class> types = new HashMap, Class>(); - types.put(boolean.class, Boolean.class); - types.put(byte.class, Byte.class); - types.put(char.class, Character.class); - types.put(double.class, Double.class); - types.put(float.class, Float.class); - types.put(int.class, Integer.class); - types.put(long.class, Long.class); - types.put(short.class, Short.class); - types.put(void.class, Void.class); - PRIMITIVE_WRAPPERS = Collections.unmodifiableMap(types); - } - - - /** - * An unknown type. - */ - public static final - class Unknown { - private - Unknown() { - } - } - - /** - * Enables the internal caching of resolved TypeVariables. (Default is true) - */ - public static - void enableCache() { - CACHE_ENABLED = true; - } - - /** - * Disables the internal caching of resolved TypeVariables. (Default is true) - */ - public static - void disableCache() { - TYPE_VARIABLE_CACHE.clear(); - CACHE_ENABLED = false; - } - - /** - * Returns the raw class representing the argument for the {@code type} using type variable information from the - * {@code subType}. If no arguments can be resolved then {@code Unknown.class} is returned. - * - * @param type to resolve argument for - * @param subType to extract type variable information from - * - * @return argument for {@code type} else {@link Unknown}.class if no type arguments are declared - * - * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code type} - */ - public static - Class resolveRawArgument(Class type, Class subType) { - return resolveRawArgument(resolveGenericType(type, subType), subType); - } - - /** - * Returns the raw class representing the argument for the {@code genericType} using type variable information from - * the {@code subType}. If {@code genericType} is an instance of class, then {@code genericType} is returned. If no - * arguments can be resolved then {@code Unknown.class} is returned. - * - * @param genericType to resolve argument for - * @param subType to extract type variable information from - * - * @return argument for {@code genericType} else {@link Unknown}.class if no type arguments are declared - * - * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code genericType} - */ - public static - Class resolveRawArgument(Type genericType, Class subType) { - Class[] arguments = resolveRawArguments(genericType, subType); - if (arguments == null) { - return Unknown.class; - } - - if (arguments.length != 1) { - throw new IllegalArgumentException("Expected 1 argument for generic type " + genericType + " but found " + arguments.length); - } - - return arguments[0]; - } - - /** - * Returns an array of raw classes representing arguments for the {@code type} using type variable information from - * the {@code subType}. Arguments for {@code type} that cannot be resolved are returned as {@code Unknown.class}. If - * no arguments can be resolved then {@code null} is returned. - * - * @param type to resolve arguments for - * @param subType to extract type variable information from - * - * @return array of raw classes representing arguments for the {@code type} else {@code null} if no type arguments are - * declared - */ - public static - Class[] resolveRawArguments(Class type, Class subType) { - return resolveRawArguments(resolveGenericType(type, subType), subType); - } - - /** - * Returns an array of raw classes representing arguments for the {@code genericType} using type variable information - * from the {@code subType}. Arguments for {@code genericType} that cannot be resolved are returned as - * {@code Unknown.class}. If no arguments can be resolved then {@code null} is returned. - * - * @param genericType to resolve arguments for - * @param subType to extract type variable information from - * - * @return array of raw classes representing arguments for the {@code genericType} else {@code null} if no type - * arguments are declared - */ - public static - Class[] resolveRawArguments(Type genericType, Class subType) { - Class[] result = null; - Class functionalInterface = null; - - // Handle lambdas - if (RESOLVES_LAMBDAS && subType.isSynthetic()) { - Class fi = genericType instanceof ParameterizedType && ((ParameterizedType) genericType).getRawType() instanceof Class - ? (Class) ((ParameterizedType) genericType).getRawType() - : genericType instanceof Class ? (Class) genericType : null; - if (fi != null && fi.isInterface()) { - functionalInterface = fi; - } - } - - if (genericType instanceof ParameterizedType) { - ParameterizedType paramType = (ParameterizedType) genericType; - Type[] arguments = paramType.getActualTypeArguments(); - result = new Class[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - result[i] = resolveRawClass(arguments[i], subType, functionalInterface); - } - } - else if (genericType instanceof TypeVariable) { - result = new Class[1]; - result[0] = resolveRawClass(genericType, subType, functionalInterface); - } - else if (genericType instanceof Class) { - TypeVariable[] typeParams = ((Class) genericType).getTypeParameters(); - result = new Class[typeParams.length]; - for (int i = 0; i < typeParams.length; i++) { - result[i] = resolveRawClass(typeParams[i], subType, functionalInterface); - } - } - - return result; - } - - /** - * Returns the generic {@code type} using type variable information from the {@code subType} else {@code null} if the - * generic type cannot be resolved. - * - * @param type to resolve generic type for - * @param subType to extract type variable information from - * - * @return generic {@code type} else {@code null} if it cannot be resolved - */ - public static - Type resolveGenericType(Class type, Type subType) { - Class rawType; - if (subType instanceof ParameterizedType) { - rawType = (Class) ((ParameterizedType) subType).getRawType(); - } - else { - rawType = (Class) subType; - } - - if (type.equals(rawType)) { - return subType; - } - - Type result; - if (type.isInterface()) { - for (Type superInterface : rawType.getGenericInterfaces()) { - if (superInterface != null && !superInterface.equals(Object.class)) { - if ((result = resolveGenericType(type, superInterface)) != null) { - return result; - } - } - } - } - - Type superClass = rawType.getGenericSuperclass(); - if (superClass != null && !superClass.equals(Object.class)) { - if ((result = resolveGenericType(type, superClass)) != null) { - return result; - } - } - - return null; - } - - /** - * Resolves the raw class for the {@code genericType}, using the type variable information from the {@code subType} - * else {@link Unknown} if the raw class cannot be resolved. - * - * @param genericType to resolve raw class for - * @param subType to extract type variable information from - * - * @return raw class for the {@code genericType} else {@link Unknown} if it cannot be resolved - */ - public static - Class resolveRawClass(Type genericType, Class subType) { - return resolveRawClass(genericType, subType, null); - } - - private static - Class resolveRawClass(Type genericType, Class subType, Class functionalInterface) { - if (genericType instanceof Class) { - return (Class) genericType; - } - else if (genericType instanceof ParameterizedType) { - return resolveRawClass(((ParameterizedType) genericType).getRawType(), subType, functionalInterface); - } - else if (genericType instanceof GenericArrayType) { - GenericArrayType arrayType = (GenericArrayType) genericType; - Class component = resolveRawClass(arrayType.getGenericComponentType(), subType, functionalInterface); - return Array.newInstance(component, 0) - .getClass(); - } - else if (genericType instanceof TypeVariable) { - TypeVariable variable = (TypeVariable) genericType; - genericType = getTypeVariableMap(subType, functionalInterface).get(variable); - genericType = genericType == null ? resolveBound(variable) : resolveRawClass(genericType, subType, functionalInterface); - } - - return genericType instanceof Class ? (Class) genericType : Unknown.class; - } - - private static - Map, Type> getTypeVariableMap(final Class targetType, Class functionalInterface) { - Reference, Type>> ref = TYPE_VARIABLE_CACHE.get(targetType); - Map, Type> map = ref != null ? ref.get() : null; - - if (map == null) { - map = new HashMap, Type>(); - - // Populate lambdas - if (functionalInterface != null) { - populateLambdaArgs(functionalInterface, targetType, map); - } - - // Populate interfaces - populateSuperTypeArgs(targetType.getGenericInterfaces(), map, functionalInterface != null); - - // Populate super classes and interfaces - Type genericType = targetType.getGenericSuperclass(); - Class type = targetType.getSuperclass(); - while (type != null && !Object.class.equals(type)) { - if (genericType instanceof ParameterizedType) { - populateTypeArgs((ParameterizedType) genericType, map, false); - } - populateSuperTypeArgs(type.getGenericInterfaces(), map, false); - - genericType = type.getGenericSuperclass(); - type = type.getSuperclass(); - } - - // Populate enclosing classes - type = targetType; - while (type.isMemberClass()) { - genericType = type.getGenericSuperclass(); - if (genericType instanceof ParameterizedType) { - populateTypeArgs((ParameterizedType) genericType, map, functionalInterface != null); - } - - type = type.getEnclosingClass(); - } - - if (CACHE_ENABLED) { - TYPE_VARIABLE_CACHE.put(targetType, new WeakReference, Type>>(map)); - } - } - - return map; - } - - /** - * Populates the {@code map} with with variable/argument pairs for the given {@code types}. - */ - private static - void populateSuperTypeArgs(final Type[] types, final Map, Type> map, boolean depthFirst) { - for (Type type : types) { - if (type instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) type; - if (!depthFirst) { - populateTypeArgs(parameterizedType, map, depthFirst); - } - Type rawType = parameterizedType.getRawType(); - if (rawType instanceof Class) { - populateSuperTypeArgs(((Class) rawType).getGenericInterfaces(), map, depthFirst); - } - if (depthFirst) { - populateTypeArgs(parameterizedType, map, depthFirst); - } - } - else if (type instanceof Class) { - populateSuperTypeArgs(((Class) type).getGenericInterfaces(), map, depthFirst); - } - } - } - - /** - * Populates the {@code map} with variable/argument pairs for the given {@code type}. - */ - private static - void populateTypeArgs(ParameterizedType type, Map, Type> map, boolean depthFirst) { - if (type.getRawType() instanceof Class) { - TypeVariable[] typeVariables = ((Class) type.getRawType()).getTypeParameters(); - Type[] typeArguments = type.getActualTypeArguments(); - - if (type.getOwnerType() != null) { - Type owner = type.getOwnerType(); - if (owner instanceof ParameterizedType) { - populateTypeArgs((ParameterizedType) owner, map, depthFirst); - } - } - - for (int i = 0; i < typeArguments.length; i++) { - TypeVariable variable = typeVariables[i]; - Type typeArgument = typeArguments[i]; - - if (typeArgument instanceof Class) { - map.put(variable, typeArgument); - } - else if (typeArgument instanceof GenericArrayType) { - map.put(variable, typeArgument); - } - else if (typeArgument instanceof ParameterizedType) { - map.put(variable, typeArgument); - } - else if (typeArgument instanceof TypeVariable) { - TypeVariable typeVariableArgument = (TypeVariable) typeArgument; - if (depthFirst) { - Type existingType = map.get(variable); - if (existingType != null) { - map.put(typeVariableArgument, existingType); - continue; - } - } - - Type resolvedType = map.get(typeVariableArgument); - if (resolvedType == null) { - resolvedType = resolveBound(typeVariableArgument); - } - map.put(variable, resolvedType); - } - } - } - } - - /** - * Resolves the first bound for the {@code typeVariable}, returning {@code Unknown.class} if none can be resolved. - */ - public static - Type resolveBound(TypeVariable typeVariable) { - Type[] bounds = typeVariable.getBounds(); - if (bounds.length == 0) { - return Unknown.class; - } - - Type bound = bounds[0]; - if (bound instanceof TypeVariable) { - bound = resolveBound((TypeVariable) bound); - } - - return bound == Object.class ? Unknown.class : bound; - } - - /** - * Populates the {@code map} with variable/argument pairs for the {@code functionalInterface}. - */ - private static - void populateLambdaArgs(Class functionalInterface, final Class lambdaType, Map, Type> map) { - if (RESOLVES_LAMBDAS) { - // Find SAM - for (Method m : functionalInterface.getMethods()) { - if (!isDefaultMethod(m) && !Modifier.isStatic(m.getModifiers()) && !m.isBridge()) { - // Skip methods that override Object.class - Method objectMethod = OBJECT_METHODS.get(m.getName()); - if (objectMethod != null && Arrays.equals(m.getTypeParameters(), objectMethod.getTypeParameters())) { - continue; - } - - // Get functional interface's type params - Type returnTypeVar = m.getGenericReturnType(); - Type[] paramTypeVars = m.getGenericParameterTypes(); - - Member member = getMemberRef(lambdaType); - if (member == null) { - return; - } - - // Populate return type argument - if (returnTypeVar instanceof TypeVariable) { - Class returnType = member instanceof Method - ? ((Method) member).getReturnType() - : ((Constructor) member).getDeclaringClass(); - returnType = wrapPrimitives(returnType); - if (!returnType.equals(Void.class)) { - map.put((TypeVariable) returnTypeVar, returnType); - } - } - - Class[] arguments = member instanceof Method - ? ((Method) member).getParameterTypes() - : ((Constructor) member).getParameterTypes(); - - // Populate object type from arbitrary object method reference - int paramOffset = 0; - if (paramTypeVars.length > 0 && paramTypeVars[0] instanceof TypeVariable && - paramTypeVars.length == arguments.length + 1) { - Class instanceType = member.getDeclaringClass(); - map.put((TypeVariable) paramTypeVars[0], instanceType); - paramOffset = 1; - } - - // Handle additional arguments that are captured from the lambda's enclosing scope - int argOffset = 0; - if (paramTypeVars.length < arguments.length) { - argOffset = arguments.length - paramTypeVars.length; - } - - // Populate type arguments - for (int i = 0; i + argOffset < arguments.length; i++) { - if (paramTypeVars[i] instanceof TypeVariable) { - map.put((TypeVariable) paramTypeVars[i + paramOffset], wrapPrimitives(arguments[i + argOffset])); - } - } - - return; - } - } - } - } - - private static - boolean isDefaultMethod(Method m) { - return OS.javaVersion >= 8 && DefaultMethodHelper.isDefaultMethod(m); - } - - private static - Member getMemberRef(Class type) { - Object constantPool; - try { - constantPool = GET_CONSTANT_POOL.invoke(type); - } catch (Exception ignore) { - return null; - } - - Member result = null; - for (int i = getConstantPoolSize(constantPool) - 1; i >= 0; i--) { - Member member = getConstantPoolMethodAt(constantPool, i); - // Skip SerializedLambda constructors and members of the "type" class - if (member == null || (member instanceof Constructor && member.getDeclaringClass() - .getName() - .equals("java.lang.invoke.SerializedLambda")) || - member.getDeclaringClass() - .isAssignableFrom(type)) { - continue; - } - - result = member; - - // Return if not valueOf method - if (!(member instanceof Method) || !isAutoBoxingMethod((Method) member)) { - break; - } - } - - return result; - } - - private static - boolean isAutoBoxingMethod(Method method) { - Class[] parameters = method.getParameterTypes(); - return method.getName() - .equals("valueOf") && parameters.length == 1 && parameters[0].isPrimitive() && wrapPrimitives(parameters[0]).equals( - method.getDeclaringClass()); - } - - private static - Class wrapPrimitives(Class clazz) { - return clazz.isPrimitive() ? PRIMITIVE_WRAPPERS.get(clazz) : clazz; - } - - private static - int getConstantPoolSize(Object constantPool) { - try { - return (Integer) GET_CONSTANT_POOL_SIZE.invoke(constantPool); - } catch (Exception ignore) { - return 0; - } - } - - private static - Member getConstantPoolMethodAt(Object constantPool, int i) { - try { - return (Member) GET_CONSTANT_POOL_METHOD_AT.invoke(constantPool, i); - } catch (Exception ignore) { - return null; - } - } - - private - TypeResolver() { - } -} diff --git a/src/dorkbox/util/serialization/ArraysAsListSerializer.java b/src/dorkbox/util/serialization/ArraysAsListSerializer.java deleted file mode 100644 index 78833c9..0000000 --- a/src/dorkbox/util/serialization/ArraysAsListSerializer.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2010 Martin Grotzke - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dorkbox.util.serialization; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.Output; - -/** - * A kryo {@link Serializer} for lists created via {@link Arrays#asList(Object...)}. - *

- * Note: This serializer does not support cyclic references, so if one of the objects - * gets set the list as attribute this might cause an error during deserialization. - *

- * - * @author Martin Grotzke - */ -public -class ArraysAsListSerializer extends Serializer> { - - private static - Class getPrimitiveWrapperClass(final Class c) { - if (c.isPrimitive()) { - if (c.equals(Long.TYPE)) { - return Long.class; - } - else if (c.equals(Integer.TYPE)) { - return Integer.class; - } - else if (c.equals(Double.TYPE)) { - return Double.class; - } - else if (c.equals(Float.TYPE)) { - return Float.class; - } - else if (c.equals(Boolean.TYPE)) { - return Boolean.class; - } - else if (c.equals(Character.TYPE)) { - return Character.class; - } - else if (c.equals(Short.TYPE)) { - return Short.class; - } - else if (c.equals(Byte.TYPE)) { - return Byte.class; - } - } - return c; - } - private Field _arrayField; - - public - ArraysAsListSerializer() { - try { - _arrayField = Class.forName("java.util.Arrays$ArrayList") - .getDeclaredField("a"); - _arrayField.setAccessible(true); - } catch (final Exception e) { - throw new RuntimeException(e); - } - // Immutable causes #copy(obj) to return the original object - setImmutable(true); - } - - @Override - public - void write(final Kryo kryo, final Output output, final List obj) { - try { - final Object[] array = (Object[]) _arrayField.get(obj); - output.writeInt(array.length, true); - final Class componentType = array.getClass() - .getComponentType(); - kryo.writeClass(output, componentType); - for (final Object item : array) { - kryo.writeClassAndObject(output, item); - } - } catch (final RuntimeException e) { - // Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write... - // handles SerializationException specifically (resizing the buffer)... - throw e; - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public - List read(final Kryo kryo, final Input input, final Class> type) { - final int length = input.readInt(true); - Class componentType = kryo.readClass(input) - .getType(); - if (componentType.isPrimitive()) { - componentType = getPrimitiveWrapperClass(componentType); - } - try { - final Object items = Array.newInstance(componentType, length); - for (int i = 0; i < length; i++) { - Array.set(items, i, kryo.readClassAndObject(input)); - } - return Arrays.asList((Object[]) items); - } catch (final Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/dorkbox/util/serialization/FieldAnnotationAwareSerializer.java b/src/dorkbox/util/serialization/FieldAnnotationAwareSerializer.java deleted file mode 100644 index 89767cc..0000000 --- a/src/dorkbox/util/serialization/FieldAnnotationAwareSerializer.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2010 Martin Grotzke - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package dorkbox.util.serialization; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.factories.SerializerFactory; -import com.esotericsoftware.kryo.serializers.FieldSerializer; - -/** - * A kryo {@link FieldSerializer} that allows to exclusively include or exclude fields that - * are attributed with user-specific annotations. This can be for example useful when serializing beans that carry - * references to a dependency injection framework. As an example for Spring: - *

- *

- * {@code
- * Set> marks = new HashSet<>();
- * marks.add(Autowired.class);
- * SerializerFactory disregardingFactory = new FieldAnnotationAwareSerializer.Factory(marks, true);
- * Kryo kryo = new Kryo();
- * kryo.setDefaultSerializer(factory);
- * }
- * 
- *

- * The resulting {@link Kryo} instance would ignore all fields that are annotated with Spring's {@code @Autowired} - * annotation. - *

- * Similarly, it is possible to created a serializer which does the opposite such that the resulting serializer - * would only serialize fields that are annotated with the specified annotations. - * - * @author Rafael Winterhalter - * @author Martin Grotzke - */ -public -class FieldAnnotationAwareSerializer extends FieldSerializer { - - /** - * A factory for creating instances of {@link FieldAnnotationAwareSerializer}. - */ - public static - class Factory implements SerializerFactory { - - private final Collection> marked; - private final boolean disregarding; - - /** - * Creates a new factory. See {@link FieldAnnotationAwareSerializer#FieldAnnotationAwareSerializer( - *com.esotericsoftware.kryo.Kryo, Class, java.util.Collection, boolean)} - * for additional information on the constructor parameters. - * - * @param marked The annotations that will be considered of the resulting converter. - * @param disregarding If {@code true}, the serializer will ignore all annotated fields, - * if set to {@code false} it will exclusively look at annotated fields. - */ - public - Factory(final Collection> marked, final boolean disregarding) { - this.marked = marked; - this.disregarding = disregarding; - } - - @Override - public - Serializer makeSerializer(final Kryo kryo, final Class type) { - return new FieldAnnotationAwareSerializer(kryo, type, this.marked, this.disregarding); - } - } - - - private final Set> marked; - - /** - * Determines whether annotated fields should be excluded from serialization. - *

- * {@code true} if annotated fields should be excluded from serialization, - * {@code false} if only annotated fields should be included from serialization. - */ - private final boolean disregarding; - - /** - * Creates a new field annotation aware serializer. - * - * @param kryo The {@link Kryo} instace. - * @param type The type of the class being serialized. - * @param marked The annotations this serializer considers for its serialization process. Be aware tha - * a serializer with {@code disregarding} set to {@code false} will never be able to - * serialize fields that are not annotated with any of these annotations since it is not - * possible to add fields to a {@link FieldSerializer} once it is created. See the - * documentation to {@link FieldAnnotationAwareSerializer#addAnnotation(Class)} and - * {@link FieldAnnotationAwareSerializer#removeAnnotation(Class)} for further information. - * @param disregarding If {@code true}, the serializer will ignore all annotated fields, - * if set to {@code false} it will exclusively look at annotated fields. - */ - public - FieldAnnotationAwareSerializer(final Kryo kryo, - final Class type, - final Collection> marked, - final boolean disregarding) { - super(kryo, type); - this.disregarding = disregarding; - this.marked = new HashSet>(marked); - rebuildCachedFields(); - } - - @Override - protected - void rebuildCachedFields() { - // In order to avoid rebuilding the cached fields twice, the super constructor's call - // to this method will be suppressed. This can be done by a simple check of the initialization - // state of a property of this subclass. - if (this.marked == null) { - return; - } - super.rebuildCachedFields(); - removeFields(); - } - - private - void removeFields() { - final CachedField[] cachedFields = getFields(); - for (final CachedField cachedField : cachedFields) { - final Field field = cachedField.getField(); - if (isRemove(field)) { -// if (TRACE) { -// trace("kryo", String.format("Ignoring field %s tag: %s", this.disregarding ? "without" : "with", cachedField)); -// } - super.removeField(field.getName()); - } - } - } - - private - boolean isRemove(final Field field) { - return !isMarked(field) ^ this.disregarding; - } - - private - boolean isMarked(final Field field) { - for (final Annotation annotation : field.getAnnotations()) { - final Class annotationType = annotation.annotationType(); - if (this.marked.contains(annotationType)) { - return true; - } - } - return false; - } - - /** - * Adds an annotation to the annotations that are considered by this serializer. - *

- * Important: This will not have an effect if the serializer was configured - * to exclusively serialize annotated fields by setting {@code disregarding} to - * {@code false}. This is similar to the contract of this serializer's superclass - * {@link FieldSerializer} which does not allow to add fields that were formerly - * removed. If this was possible, instances that were serialized before this field - * was added could not longer be properly deserialized. In order to make this contract - * break explicit, you need to create a new instance of this serializer if you want to - * include new fields to a serializer that exclusively serializes annotated fields. - * - * @param clazz The annotation class to be added. - * - * @return {@code true} if the method call had an effect. - */ - public - boolean addAnnotation(final Class clazz) { - if (this.disregarding && this.marked.add(clazz)) { - initializeCachedFields(); - return true; - } - return false; - } - - /** - * Removes an annotation to the annotations that are considered by this serializer. - *

- * Important: This will not have an effect if the serializer was configured - * to not serialize annotated fields by setting {@code disregarding} to - * {@code true}. This is similar to the contract of this serializer's superclass - * {@link FieldSerializer} which does not allow to add fields that were formerly - * removed. If this was possible, instances that were serialized before this field - * was added could not longer be properly deserialized. In order to make this contract - * break explicit, you need to create a new instance of this serializer if you want to - * include new fields to a serializer that ignores annotated fields for serialization. - * - * @param clazz The annotation class to be removed. - * - * @return {@code true} if the method call had an effect. - */ - public - boolean removeAnnotation(final Class clazz) { - if (!this.disregarding && this.marked.remove(clazz)) { - initializeCachedFields(); - return true; - } - return false; - } -} diff --git a/src/dorkbox/util/serialization/FileSerializer.java b/src/dorkbox/util/serialization/FileSerializer.java index 786f05c..71f9e7a 100644 --- a/src/dorkbox/util/serialization/FileSerializer.java +++ b/src/dorkbox/util/serialization/FileSerializer.java @@ -21,7 +21,7 @@ class FileSerializer extends Serializer { @Override public - File read(Kryo kryo, Input input, Class type) { + File read(final Kryo kryo, final Input input, final Class type) { String path = input.readString(); return new File(path); } diff --git a/src/dorkbox/util/serialization/UnmodifiableCollectionsSerializer.java b/src/dorkbox/util/serialization/UnmodifiableCollectionsSerializer.java deleted file mode 100644 index e9c1cde..0000000 --- a/src/dorkbox/util/serialization/UnmodifiableCollectionsSerializer.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2010 Martin Grotzke - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package dorkbox.util.serialization; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.Output; - -/** - * A kryo {@link Serializer} for unmodifiable {@link Collection}s and {@link Map}s - * created via {@link Collections}. - * - * @author Martin Grotzke - */ -public -class UnmodifiableCollectionsSerializer extends Serializer { - - private - enum UnmodifiableCollection { - COLLECTION(Collections.unmodifiableCollection(Arrays.asList("")) - .getClass(), SOURCE_COLLECTION_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableCollection((Collection) sourceCollection); - } - }, RANDOM_ACCESS_LIST(Collections.unmodifiableList(new ArrayList()) - .getClass(), SOURCE_COLLECTION_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableList((List) sourceCollection); - } - }, LIST(Collections.unmodifiableList(new LinkedList()) - .getClass(), SOURCE_COLLECTION_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableList((List) sourceCollection); - } - }, SET(Collections.unmodifiableSet(new HashSet()) - .getClass(), SOURCE_COLLECTION_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableSet((Set) sourceCollection); - } - }, SORTED_SET(Collections.unmodifiableSortedSet(new TreeSet()) - .getClass(), SOURCE_COLLECTION_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableSortedSet((SortedSet) sourceCollection); - } - }, MAP(Collections.unmodifiableMap(new HashMap()) - .getClass(), SOURCE_MAP_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableMap((Map) sourceCollection); - } - - }, SORTED_MAP(Collections.unmodifiableSortedMap(new TreeMap()) - .getClass(), SOURCE_MAP_FIELD) { - @Override - public - Object create(final Object sourceCollection) { - return Collections.unmodifiableSortedMap((SortedMap) sourceCollection); - } - }; - - static - UnmodifiableCollection valueOfType(final Class type) { - for (final UnmodifiableCollection item : values()) { - if (item.type.equals(type)) { - return item; - } - } - throw new IllegalArgumentException("The type " + type + " is not supported."); - } - private final Class type; - private final Field sourceCollectionField; - - UnmodifiableCollection(final Class type, final Field sourceCollectionField) { - this.type = type; - this.sourceCollectionField = sourceCollectionField; - } - - public abstract - Object create(Object sourceCollection); - - } - private static final Field SOURCE_COLLECTION_FIELD; - private static final Field SOURCE_MAP_FIELD; - - static { - try { - SOURCE_COLLECTION_FIELD = Class.forName("java.util.Collections$UnmodifiableCollection") - .getDeclaredField("c"); - SOURCE_COLLECTION_FIELD.setAccessible(true); - - - SOURCE_MAP_FIELD = Class.forName("java.util.Collections$UnmodifiableMap") - .getDeclaredField("m"); - SOURCE_MAP_FIELD.setAccessible(true); - } catch (final Exception e) { - throw new RuntimeException("Could not access source collection" + " field in java.util.Collections$UnmodifiableCollection.", e); - } - } - - /** - * Creates a new {@link UnmodifiableCollectionsSerializer} and registers its serializer - * for the several unmodifiable Collections that can be created via {@link Collections}, - * including {@link Map}s. - * - * @param manager the {@link SerializationManager} instance to set the serializer on. - * - * @see Collections#unmodifiableCollection(Collection) - * @see Collections#unmodifiableList(List) - * @see Collections#unmodifiableSet(Set) - * @see Collections#unmodifiableSortedSet(SortedSet) - * @see Collections#unmodifiableMap(Map) - * @see Collections#unmodifiableSortedMap(SortedMap) - */ - public static - void registerSerializers(final SerializationManager manager) { - final UnmodifiableCollectionsSerializer serializer = new UnmodifiableCollectionsSerializer(); - UnmodifiableCollection.values(); - for (final UnmodifiableCollection item : UnmodifiableCollection.values()) { - manager.register(item.type, serializer); - } - } - - @Override - public - void write(final Kryo kryo, final Output output, final Object object) { - try { - final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.valueOfType(object.getClass()); - // the ordinal could be replaced by s.th. else (e.g. a explicitely managed "id") - output.writeInt(unmodifiableCollection.ordinal(), true); - kryo.writeClassAndObject(output, unmodifiableCollection.sourceCollectionField.get(object)); - } catch (final RuntimeException e) { - // Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write... - // handles SerializationException specifically (resizing the buffer)... - throw e; - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public - Object read(final Kryo kryo, final Input input, final Class clazz) { - final int ordinal = input.readInt(true); - final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.values()[ordinal]; - final Object sourceCollection = kryo.readClassAndObject(input); - return unmodifiableCollection.create(sourceCollection); - } - - @Override - public - Object copy(Kryo kryo, Object original) { - try { - final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.valueOfType(original.getClass()); - Object sourceCollectionCopy = kryo.copy(unmodifiableCollection.sourceCollectionField.get(original)); - return unmodifiableCollection.create(sourceCollectionCopy); - } catch (final RuntimeException e) { - // Don't eat and wrap RuntimeExceptions - throw e; - } catch (final Exception e) { - throw new RuntimeException(e); - } - } -}