📄 classstreamhandler.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.wicket.util.io;import java.io.IOException;import java.io.NotSerializableException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamClass;import java.io.Serializable;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.Proxy;import java.security.AccessController;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import sun.misc.Unsafe;import sun.reflect.ReflectionFactory;/** * TODO DOC ME! * * NOTE: this class uses Sun-specific features: we use {@link Unsafe} because we need to set the * final fields, and we use {@link ReflectionFactory} to be able to find constructors appropriate * for serialization. * * @author jcompagner */public final class ClassStreamHandler{ private static Unsafe unsafe; static { try { Class[] classes = ObjectStreamClass.class.getDeclaredClasses(); for (int i = 0; i < classes.length; i++) { if (classes[i].getName().equals("java.io.ObjectStreamClass$FieldReflector")) { Field unsafeField = classes[i].getDeclaredField("unsafe"); unsafeField.setAccessible(true); unsafe = (Unsafe)unsafeField.get(null); break; } } } catch (Throwable e) { // e.printStackTrace() } } private static final ReflectionFactory reflFactory = (ReflectionFactory)AccessController .doPrivileged(new ReflectionFactory.GetReflectionFactoryAction()); private static Map handlesClasses = new HashMap(); private static short classCounter = 0; /** * */ public static final byte HANDLE = 1; /** * */ public static final byte NULL = 0; /** * */ public static final byte CLASS_DEF = 2; /** * */ public static final byte ARRAY = 3; /** * */ public static final byte PRIMITIVE_ARRAY = 4; /** * */ public static final int CLASS = 5; static ClassStreamHandler lookup(Class cls) throws NotSerializableException { ClassStreamHandler classHandler = (ClassStreamHandler)handlesClasses.get(cls.getName()); if (classHandler == null) { classHandler = new ClassStreamHandler(cls); handlesClasses.put(cls.getName(), classHandler); handlesClasses.put(new Short(classHandler.getClassId()), classHandler); } return classHandler; } static ClassStreamHandler lookup(short s) { ClassStreamHandler classHandler = (ClassStreamHandler)handlesClasses.get(new Short(s)); if (classHandler == null) { throw new RuntimeException("class not found for: " + s); } return classHandler; } /** * */ private final Class clz; private final List fields; private final short classId; private final Constructor cons; private final Method writeReplaceMethod; private final Method readResolveMethod; private final List writeObjectMethods; private final List readObjectMethods; private final PrimitiveArray primitiveArray; /** * Construct. * * @param cls * TODO * @throws WicketSerializeableException */ private ClassStreamHandler(Class cls) throws WicketSerializeableException { this.classId = classCounter++; this.clz = cls; if (cls.isPrimitive()) { fields = null; cons = null; writeObjectMethods = null; readObjectMethods = null; writeReplaceMethod = null; readResolveMethod = null; if (clz == boolean.class) { primitiveArray = new BooleanPrimitiveArray(); } else if (clz == byte.class) { primitiveArray = new BytePrimitiveArray(); } else if (clz == short.class) { primitiveArray = new ShortPrimitiveArray(); } else if (clz == char.class) { primitiveArray = new CharPrimitiveArray(); } else if (clz == int.class) { primitiveArray = new IntPrimitiveArray(); } else if (clz == long.class) { primitiveArray = new LongPrimitiveArray(); } else if (clz == float.class) { primitiveArray = new FloatPrimitiveArray(); } else if (clz == double.class) { primitiveArray = new DoublePrimitiveArray(); } else { throw new RuntimeException("Unsupported primitive " + cls); } } else if (cls.isInterface()) { fields = null; cons = null; writeObjectMethods = null; readObjectMethods = null; writeReplaceMethod = null; readResolveMethod = null; primitiveArray = null; } else if (Proxy.isProxyClass(clz)) { fields = null; cons = null; writeObjectMethods = null; writeReplaceMethod = null; readResolveMethod = null; readObjectMethods = null; primitiveArray = null; } else { fields = new ArrayList(); primitiveArray = null; writeObjectMethods = new ArrayList(2); readObjectMethods = new ArrayList(2); writeReplaceMethod = getInheritableMethod(clz, "writeReplace", null, Object.class); readResolveMethod = getInheritableMethod(clz, "readResolve", null, Object.class); if (readResolveMethod == null) { cons = getSerializableConstructor(clz); if (cons == null) { throw new WicketSerializeableException( "No Serializable constructor found for " + cls); } } else { cons = getSerializableConstructor(clz); } Class parent = cls; while (parent != Object.class) { Method method = getPrivateMethod(parent, "writeObject", new Class[] { ObjectOutputStream.class }, Void.TYPE); if (method != null) { writeObjectMethods.add(method); } method = getPrivateMethod(parent, "readObject", new Class[] { ObjectInputStream.class }, Void.TYPE); if (method != null) { readObjectMethods.add(method); } parent = parent.getSuperclass(); } fillFields(cls); } } /** * @return */ public Class getStreamClass() { return clz; } /** * @return */ public short getClassId() { return classId; } /** * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws IllegalArgumentException */ public Object createObject() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { return cons.newInstance(null); } /** * @param cls */ private void fillFields(Class cls) { if (cls == null) { return; } Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; field.setAccessible(true); if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isTransient(field.getModifiers())) { FieldAndIndex fai = null; Class clz = field.getType(); long offset = unsafe.objectFieldOffset(field); if (clz == boolean.class) { fai = new BooleanFieldAndIndex(field); } else if (clz == byte.class) { fai = new ByteFieldAndIndex(field); } else if (clz == short.class) { fai = new ShortFieldAndIndex(field); } else if (clz == char.class) { fai = new CharFieldAndIndex(field); } else if (clz == int.class) { fai = new IntFieldAndIndex(field); } else if (clz == long.class) { fai = new LongFieldAndIndex(field); } else if (clz == float.class) { fai = new FloatFieldAndIndex(field); } else if (clz == double.class) { fai = new DoubleFieldAndIndex(field); } else { fai = new ObjectFieldAndIndex(field); } this.fields.add(fai); } } cls = cls.getSuperclass(); if (cls != Object.class) { fillFields(cls); } return; } /** * @param woos * @param obj * @throws WicketSerializeableException */ public void writeFields(WicketObjectOutputStream woos, Object obj) throws WicketSerializeableException { FieldAndIndex fai = null; try { for (int i = 0; fields != null && i < fields.size(); i++) { fai = (FieldAndIndex)fields.get(i); fai.writeField(obj, woos); } } catch (WicketSerializeableException wse) { wse.addTrace(fai.field.getName()); throw wse; } catch (Exception ex) { String field = fai == null || fai.field == null ? "" : fai.field.getName(); String msg = "Error writing field: " + field + " for object class: " + obj.getClass(); throw new WicketSerializeableException(msg, ex); } } /** * @param wois * @throws WicketSerializeableException */ public void readFields(WicketObjectInputStream wois, Object object) throws WicketSerializeableException { FieldAndIndex fai = null; try { for (int i = 0; i < fields.size(); i++) { fai = (FieldAndIndex)fields.get(i); fai.readField(object, wois); } } catch (WicketSerializeableException wse) { wse.addTrace(fai.field.getName()); throw wse; } catch (Exception ex) { throw new WicketSerializeableException("Error reading field: " + fai.field.getName() + " for object class: " + object.getClass(), ex); } } public void writeArray(Object obj, WicketObjectOutputStream wois) throws IOException { primitiveArray.writeArray(obj, wois); } public Object readArray(WicketObjectInputStream wois) throws IOException { return primitiveArray.readArray(wois); } /** * @param woos * @param obj * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ public boolean invokeWriteMethod(WicketObjectOutputStream woos, Object obj) { if ((writeObjectMethods != null) && writeObjectMethods.size() > 0) { for (int i = writeObjectMethods.size(); --i >= 0;) { Method method = (Method)writeObjectMethods.get(i); try { method.invoke(obj, new Object[] { woos }); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } } return true; } return false; } /** * @param wois * @return */ public boolean invokeReadMethod(WicketObjectInputStream wois, Object obj) { if ((readObjectMethods != null) && readObjectMethods.size() > 0) { for (int i = readObjectMethods.size(); --i >= 0;) { Method method = (Method)readObjectMethods.get(i); try { method.invoke(obj, new Object[] { wois }); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } } return true; } return false; } private static Constructor getSerializableConstructor(Class cl) { Class initCl = cl; while (Serializable.class.isAssignableFrom(initCl)) { if ((initCl = initCl.getSuperclass()) == null) { return null; } } try { Constructor cons = initCl.getDeclaredConstructor((Class[])null); int mods = cons.getModifiers(); if ((mods & Modifier.PRIVATE) != 0 || ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && !packageEquals(cl, initCl))) { return null; } cons = reflFactory.newConstructorForSerialization(cl, cons); cons.setAccessible(true); return cons; } catch (NoSuchMethodException ex) { return null; } } /** * Returns non-static private method with given signature defined by given class, or null if * none found. Access checks are disabled on the returned method (if any). */ private static Method getPrivateMethod(Class cl, String name, Class[] argTypes, Class returnType) { try { Method meth = cl.getDeclaredMethod(name, argTypes); meth.setAccessible(true); int mods = meth.getModifiers(); return ((meth.getReturnType() == returnType) && ((mods & Modifier.STATIC) == 0) && ((mods & Modifier.PRIVATE) != 0)) ? meth : null; } catch (NoSuchMethodException ex) { return null; } } /** * Returns non-static, non-abstract method with given signature provided it is defined by or * accessible (via inheritance) by the given class, or null if no match found. Access checks are * disabled on the returned method (if any). */ private static Method getInheritableMethod(Class cl, String name, Class[] argTypes, Class returnType) { Method meth = null; Class defCl = cl; while (defCl != null) { try { meth = defCl.getDeclaredMethod(name, argTypes); break; } catch (NoSuchMethodException ex) { defCl = defCl.getSuperclass(); } } if ((meth == null) || (meth.getReturnType() != returnType)) { return null; } meth.setAccessible(true); int mods = meth.getModifiers(); if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { return null; } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -