org.jboss.marshalling.AbstractClassResolver Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 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;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.HashMap;
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
}
/** {@inheritDoc} The base implementation 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 && serialVersionUID != 0L) {
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 {
final Class> prim = primitives.get(name);
return prim != null ? prim : Class.forName(name, false, getClassLoader());
}
/**
* {@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 = getClassLoader();
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);
}
private static final Map> primitives;
static {
final Map> map = new HashMap>();
map.put("void", void.class);
map.put("byte", byte.class);
map.put("short", short.class);
map.put("int", int.class);
map.put("long", long.class);
map.put("char", char.class);
map.put("boolean", boolean.class);
map.put("float", float.class);
map.put("double", double.class);
primitives = map;
}
}