/* * 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 de.javakaffee.kryoserializers.cglib; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Set; /** * Our custom implementation of the ClassLoader. * For any of classes from "javablogging" package * it will use its {@link CustomClassLoader#getClass()} * method to load it from the specific .class file. For any * other class it will use the super.loadClass() method * from ClassLoader, which will eventually pass the * request to the parent. * * @see <a href="http://www.javablogging.com/java-classloader-2-write-your-own-classloader/">Java ClassLoader (2) – Write your own ClassLoader</a> * */ public class CustomClassLoader extends ClassLoader { /** * Parent ClassLoader passed to this constructor * will be used if this ClassLoader can not resolve a * particular class. * * @param parent Parent ClassLoader * (may be from getClass().getClassLoader()) */ public CustomClassLoader(final ClassLoader parent) { super(parent); } /** * Loads a given class from .class file just like * the default ClassLoader. This method could be * changed to load the class over network from some * other server or from the database. * * @param name Full class name */ private Class<?> getClass(final String name) throws ClassNotFoundException { // We are getting a name that looks like // javablogging.package.ClassToLoad // and we have to convert it into the .class file name // like javablogging/package/ClassToLoad.class final String file = name.replace('.', File.separatorChar) + ".class"; byte[] b = null; try { // This loads the byte code data from the file b = loadClassData(file); // defineClass is inherited from the ClassLoader class // and converts the byte array into a Class final Class<?> c = defineClass(name, b, 0, b.length); resolveClass(c); return c; } catch (final IOException e) { e.printStackTrace(); return null; } } /** * Every request for a class passes through this method. * If the requested class is in "javablogging" package, * it will load it using the * {@link CustomClassLoader#getClass()} method. * If not, it will use the super.loadClass() method * which in turn will pass the request to the parent. * * @param name * Full class name */ @Override public Class<?> loadClass(final String name) throws ClassNotFoundException { System.out.println("loading class '" + name + "'"); if (name.startsWith( getClass().getPackage().getName() ) && !_definedClasses.contains( name ) ) { System.out.println("-> custom loading class '" + name + "'"); _definedClasses.add( name ); return getClass(name); } return super.loadClass(name); } private final Set<String> _definedClasses = new HashSet<String>(); /** * Loads a given file (presumably .class) into a byte array. * The file should be accessible as a resource, for example * it could be located on the classpath. * * @param name File name to load * @return Byte array read from the file * @throws IOException Is thrown when there * was some problem reading the file */ private byte[] loadClassData(final String name) throws IOException { // Opening the file final InputStream stream = getClass().getClassLoader() .getResourceAsStream(name); final int size = stream.available(); final byte buff[] = new byte[size]; final DataInputStream in = new DataInputStream(stream); // Reading the binary data in.readFully(buff); in.close(); return buff; } @Override protected void finalize() throws Throwable { System.out.println( getClass().getSimpleName() + ".finalize() is being called." ); super.finalize(); } }