1 16 17 package org.springframework.instrument.classloading; 18 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.lang.instrument.ClassFileTransformer ; 22 import java.lang.instrument.IllegalClassFormatException ; 23 import java.net.URL ; 24 import java.util.ArrayList ; 25 import java.util.Enumeration ; 26 import java.util.HashMap ; 27 import java.util.LinkedList ; 28 import java.util.List ; 29 import java.util.Map ; 30 31 import org.springframework.util.Assert; 32 import org.springframework.util.FileCopyUtils; 33 import org.springframework.util.StringUtils; 34 35 47 public class ShadowingClassLoader extends ClassLoader { 48 49 50 public static final String [] DEFAULT_EXCLUDED_PACKAGES = new String [] {"java.", "javax.", "sun.", "com.sun.", 51 "org.w3c.", "org.xml.", "org.dom4j.", "org.aspectj.", "org.apache.xerces.", "org.apache.commons.logging."}; 52 53 54 55 public final List <String > optionalExcludedPackages = new ArrayList <String >(); 56 57 private final ClassLoader enclosingClassLoader; 58 59 private final List <ClassFileTransformer > classFileTransformers = new LinkedList <ClassFileTransformer >(); 60 61 private final Map <String , Class > classCache = new HashMap <String , Class >(); 62 63 64 68 public ShadowingClassLoader(ClassLoader enclosingClassLoader) { 69 Assert.notNull(enclosingClassLoader, "Enclosing ClassLoader must not be null"); 70 this.enclosingClassLoader = enclosingClassLoader; 71 } 72 73 78 public void addTransformer(ClassFileTransformer transformer) { 79 Assert.notNull(transformer, "Transformer must not be null"); 80 this.classFileTransformers.add(transformer); 81 } 82 83 88 public void copyTransformers(ShadowingClassLoader other) { 89 Assert.notNull(other, "Other ClassLoader must not be null"); 90 this.classFileTransformers.addAll(other.classFileTransformers); 91 } 92 93 94 public Class <?> loadClass(String name) throws ClassNotFoundException { 95 if (shouldShadow(name)) { 96 Class cls = this.classCache.get(name); 97 if (cls != null) { 98 return cls; 99 } 100 return doLoadClass(name); 101 } 102 else { 103 return this.enclosingClassLoader.loadClass(name); 104 } 105 } 106 107 111 private boolean shouldShadow(String className) { 112 return (!className.equals(getClass().getName()) && !className.endsWith("ShadowingClassLoader") 113 && !isExcludedPackage(className) && !isClassNameExcludedFromShadowing(className)); 114 } 115 116 120 private boolean isExcludedPackage(String className) { 121 for (int i = 0; i < DEFAULT_EXCLUDED_PACKAGES.length; i++) { 122 if (className.startsWith(DEFAULT_EXCLUDED_PACKAGES[i])) { 123 return true; 124 } 125 } 126 for (String pkg : this.optionalExcludedPackages) { 128 if (className.startsWith(pkg)) { 129 return true; 130 } 131 } 132 return false; 133 } 134 135 140 protected boolean isClassNameExcludedFromShadowing(String className) { 141 return false; 142 } 143 144 private Class doLoadClass(String name) throws ClassNotFoundException { 145 String internalName = StringUtils.replace(name, ".", "/") + ".class"; 146 InputStream is = this.enclosingClassLoader.getResourceAsStream(internalName); 147 if (is == null) { 148 throw new ClassNotFoundException (name); 149 } 150 try { 151 byte[] bytes = FileCopyUtils.copyToByteArray(is); 152 bytes = applyTransformers(name, bytes); 153 Class cls = defineClass(name, bytes, 0, bytes.length); 154 this.classCache.put(name, cls); 155 return cls; 156 } 157 catch (IOException ex) { 158 throw new ClassNotFoundException ("Cannot load resource for class [" + name + "]", ex); 159 } 160 } 161 162 private byte[] applyTransformers(String name, byte[] bytes) { 163 String internalName = StringUtils.replace(name, ".", "/"); 164 try { 165 for (ClassFileTransformer transformer : this.classFileTransformers) { 166 byte[] transformed = transformer.transform(this, internalName, null, null, bytes); 167 bytes = (transformed != null ? transformed : bytes); 168 } 169 return bytes; 170 } 171 catch (IllegalClassFormatException ex) { 172 throw new IllegalStateException (ex); 173 } 174 } 175 176 public URL getResource(String name) { 177 return this.enclosingClassLoader.getResource(name); 178 } 179 180 public InputStream getResourceAsStream(String name) { 181 return this.enclosingClassLoader.getResourceAsStream(name); 182 } 183 184 public Enumeration <URL > getResources(String name) throws IOException { 185 return this.enclosingClassLoader.getResources(name); 186 } 187 188 191 public List <String > getOptionalExcludedPackages() { 192 return this.optionalExcludedPackages; 193 } 194 195 } 196 | Popular Tags |