org.jboss.marshalling.AbstractClassResolver Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.marshalling;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.jboss.marshalling.reflect.SerializableClassRegistry;
/**
* A base implementation of {@code ClassResolver} which simply resolves the class
* against a classloader which is specified by the subclass implementation.
*/
public abstract class AbstractClassResolver implements ClassResolver {
/**
* Specifies whether an exception should be thrown on an incorrect serialVersionUID.
*/
protected final boolean enforceSerialVersionUid;
private static final SerializableClassRegistry registry;
static {
registry = AccessController.doPrivileged(new PrivilegedAction() {
public SerializableClassRegistry run() {
return SerializableClassRegistry.getInstance();
}
});
}
/**
* Construct a new instance.
*/
protected AbstractClassResolver() {
this(false);
}
/**
* Construct a new instance.
*
* @param enforceSerialVersionUid {@code true} if an exception should be thrown on an incorrect serialVersionUID
*/
protected AbstractClassResolver(final boolean enforceSerialVersionUid) {
this.enforceSerialVersionUid = enforceSerialVersionUid;
}
/**
* Get the classloader to use to resolve classes for this resolver.
*
* @return the classloader
*/
protected abstract ClassLoader getClassLoader();
/** {@inheritDoc} The base implementation takes no action. */
public void annotateClass(final Marshaller marshaller, final Class> clazz) throws IOException {
// no operation
}
/** {@inheritDoc} The base implementation takes no action. */
public void annotateProxyClass(final Marshaller marshaller, final Class> proxyClass) throws IOException {
// no operation
}
private ClassLoader getClassLoaderChecked() throws ClassNotFoundException {
final ClassLoader loader = getClassLoader();
if (loader == null) {
throw new ClassNotFoundException("No classloader available");
}
return loader;
}
/** {@inheritDoc} The base implemenation returns the name of the class. */
public String getClassName(final Class> clazz) throws IOException {
return clazz.getName();
}
/** {@inheritDoc} The base implementation returns the name of each interface (via {@link #getClassName(Class) getClassName()} implemented by the given class. */
public String[] getProxyInterfaces(final Class> proxyClass) throws IOException {
final Class>[] interfaces = proxyClass.getInterfaces();
final String[] names = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
names[i] = getClassName(interfaces[i]);
}
return names;
}
/**
* {@inheritDoc} The base implementation uses the class loader returned from {@code getClassLoader()} and
* loads the class by name.
*/
public Class> resolveClass(final Unmarshaller unmarshaller, final String name, final long serialVersionUID) throws IOException, ClassNotFoundException {
final Class> clazz = loadClass(name);
if (enforceSerialVersionUid) {
final long uid = registry.lookup(clazz).getEffectiveSerialVersionUID();
if (uid != serialVersionUID) {
throw new StreamCorruptedException("serialVersionUID does not match!");
}
}
return clazz;
}
/**
* Load a class with the given name. The base implementation uses the classloader returned from {@link #getClassLoader()}.
*
* @param name the name of the class
* @return the class
* @throws ClassNotFoundException if the class is not found, or if there is no classloader
*/
protected Class> loadClass(final String name) throws ClassNotFoundException {
return Class.forName(name, false, getClassLoaderChecked());
}
/**
* {@inheritDoc} The base implementation uses the class loader returned from {@code getClassLoader()} and loads
* each interface by name, returning a proxy class from that class loader.
*/
public Class> resolveProxyClass(final Unmarshaller unmarshaller, final String[] interfaces) throws IOException, ClassNotFoundException {
final ClassLoader classLoader = getClassLoaderChecked();
final int length = interfaces.length;
Class>[] classes = new Class>[length];
for (int i = 0; i < length; i ++) {
classes[i] = loadClass(interfaces[i]);
}
return Proxy.getProxyClass(classLoader, classes);
}
}