All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.marshalling.reflect.JDKSpecific Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 org.jboss.marshalling.reflect;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;

import org.jboss.marshalling._private.GetReflectionFactoryAction;
import sun.reflect.ReflectionFactory;

/**
 * JDK-specific classes which are replaced for different JDK major versions. This one is for Java 8 only.
 *
 * @author Richard Opalka
 */
final class JDKSpecific {
    private JDKSpecific() {}

    static final SerializableClassRegistry REGISTRY = SerializableClassRegistry.getInstanceUnchecked();

    private static final ReflectionFactory reflectionFactory = AccessController.doPrivileged(GetReflectionFactoryAction.INSTANCE);

    static Constructor newConstructorForSerialization(Class classToInstantiate, Constructor constructorToCall) {
        return reflectionFactory.newConstructorForSerialization(classToInstantiate, constructorToCall);
    }

    static final class SerMethods {
        private final Method readObject;
        private final Method readObjectNoData;
        private final Method writeObject;
        private final Method readResolve;
        private final Method writeReplace;
        private final Constructor noArgConstructor;
        private final Constructor objectInputConstructor;

        SerMethods(Class clazz) {
            Method writeObject = null;
            Method readObject = null;
            Method readObjectNoData = null;
            Method writeReplace = null;
            Method readResolve = null;
            for (Method method : clazz.getDeclaredMethods()) {
                final int modifiers = method.getModifiers();
                final String methodName = method.getName();
                final Class methodReturnType = method.getReturnType();
                if (! Modifier.isStatic(modifiers)) {
                    if (Modifier.isPrivate(modifiers) && methodReturnType == void.class) {
                        if (methodName.equals("writeObject")) {
                            final Class[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes.length == 1 && parameterTypes[0] == ObjectOutputStream.class) {
                                writeObject = method;
                                writeObject.setAccessible(true);
                            }
                        } else if (methodName.equals("readObject")) {
                            final Class[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes.length == 1 && parameterTypes[0] == ObjectInputStream.class) {
                                readObject = method;
                                readObject.setAccessible(true);
                            }
                        } else if (methodName.equals("readObjectNoData")) {
                            final Class[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes.length == 0) {
                                readObjectNoData = method;
                                readObjectNoData.setAccessible(true);
                            }
                        }
                    } else if (methodReturnType == Object.class) {
                        // inheritable
                        if (methodName.equals("writeReplace")) {
                            final Class[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes.length == 0) {
                                writeReplace = method;
                                writeReplace.setAccessible(true);
                            }
                        } else if (methodName.equals("readResolve")) {
                            final Class[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes.length == 0) {
                                readResolve = method;
                                readResolve.setAccessible(true);
                            }
                        }
                    }
                }
            }
            if (readResolve == null || writeReplace == null) {
                final Class superclass = clazz.getSuperclass();
                if (superclass != null) {
                    final SerializableClass superInfo = REGISTRY.lookup(superclass);
                    final Method otherReadResolve = superInfo.getSerMethods().readResolve;
                    if (readResolve == null && otherReadResolve != null && ! Modifier.isPrivate(otherReadResolve.getModifiers())) {
                        readResolve = otherReadResolve;
                    }
                    final Method otherWriteReplace = superInfo.getSerMethods().writeReplace;
                    if (writeReplace == null && otherWriteReplace != null && ! Modifier.isPrivate(otherWriteReplace.getModifiers())) {
                        writeReplace = otherWriteReplace;
                    }
                }
            }
            this.readObject = readObject;
            this.readObjectNoData = readObjectNoData;
            this.writeObject = writeObject;
            this.readResolve = readResolve;
            this.writeReplace = writeReplace;
            Constructor noArgConstructor = null;
            Constructor objectInputConstructor = null;
            for (Constructor constructor : clazz.getDeclaredConstructors()) {
                final Class[] parameterTypes = constructor.getParameterTypes();
                if (parameterTypes.length == 0) {
                    noArgConstructor = constructor;
                    noArgConstructor.setAccessible(true);
                } else if (parameterTypes.length == 1 && parameterTypes[0] == ObjectInput.class) {
                    objectInputConstructor = constructor;
                    objectInputConstructor.setAccessible(true);
                }
            }
            this.noArgConstructor = noArgConstructor;
            this.objectInputConstructor = objectInputConstructor;
        }

        boolean hasWriteObject() {
            return writeObject != null;
        }

        void callWriteObject(Object object, ObjectOutputStream outputStream) throws IOException {
            try {
                writeObject.invoke(object, outputStream);
            } catch (InvocationTargetException e) {
                final Throwable te = e.getTargetException();
                if (te instanceof IOException) {
                    throw (IOException)te;
                } else if (te instanceof RuntimeException) {
                    throw (RuntimeException)te;
                } else if (te instanceof Error) {
                    throw (Error)te;
                } else {
                    throw new IllegalStateException("Unexpected exception", te);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Method is unexpectedly inaccessible");
            }
        }

        boolean hasReadObject() {
            return readObject != null;
        }

        void callReadObject(Object object, ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
            try {
                readObject.invoke(object, inputStream);
            } catch (InvocationTargetException e) {
                final Throwable te = e.getTargetException();
                if (te instanceof IOException) {
                    throw (IOException)te;
                } else if (te instanceof ClassNotFoundException) {
                    throw (ClassNotFoundException)te;
                } else if (te instanceof RuntimeException) {
                    throw (RuntimeException)te;
                } else if (te instanceof Error) {
                    throw (Error)te;
                } else {
                    throw new IllegalStateException("Unexpected exception", te);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Method is unexpectedly inaccessible");
            }
        }

        boolean hasReadObjectNoData() {
            return readObjectNoData != null;
        }

        void callReadObjectNoData(Object object) throws ObjectStreamException {
            try {
                readObjectNoData.invoke(object);
            } catch (InvocationTargetException e) {
                final Throwable te = e.getTargetException();
                if (te instanceof ObjectStreamException) {
                    throw (ObjectStreamException)te;
                } else if (te instanceof RuntimeException) {
                    throw (RuntimeException)te;
                } else if (te instanceof Error) {
                    throw (Error)te;
                } else {
                    throw new IllegalStateException("Unexpected exception", te);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Method is unexpectedly inaccessible");
            }
        }

        boolean hasWriteReplace() {
            return writeReplace != null;
        }

        Object callWriteReplace(Object object) throws ObjectStreamException {
            try {
                return writeReplace.invoke(object);
            } catch (InvocationTargetException e) {
                final Throwable te = e.getTargetException();
                if (te instanceof ObjectStreamException) {
                    throw (ObjectStreamException)te;
                } else if (te instanceof RuntimeException) {
                    throw (RuntimeException)te;
                } else if (te instanceof Error) {
                    throw (Error)te;
                } else {
                    throw new IllegalStateException("Unexpected exception", te);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Method is unexpectedly inaccessible");
            }
        }

        boolean hasReadResolve() {
            return readResolve != null;
        }

        Object callReadResolve(Object object) throws ObjectStreamException {
            try {
                return readResolve.invoke(object);
            } catch (InvocationTargetException e) {
                final Throwable te = e.getTargetException();
                if (te instanceof ObjectStreamException) {
                    throw (ObjectStreamException)te;
                } else if (te instanceof RuntimeException) {
                    throw (RuntimeException)te;
                } else if (te instanceof Error) {
                    throw (Error)te;
                } else {
                    throw new IllegalStateException("Unexpected exception", te);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Method is unexpectedly inaccessible");
            }
        }

        Constructor getNoArgConstructor() {
            return noArgConstructor;
        }

        Constructor getObjectInputConstructor() {
            return objectInputConstructor;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy