1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.bind.v2; 27 28 import java.lang.reflect.Constructor; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.lang.reflect.Modifier; 32 import java.lang.ref.WeakReference; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 import java.util.Map; 36 import java.util.WeakHashMap; 37 import java.util.logging.Level; 38 import java.util.logging.Logger; 39 40 import com.sun.xml.internal.bind.Util; 41 42 /** 43 * Creates new instances of classes. 44 * 45 * <p> 46 * This code handles the case where the class is not public or the constructor is 47 * not public. 48 * 49 * @since 2.0 50 * @author Kohsuke Kawaguchi 51 */ 52 public final class ClassFactory { 53 private static final Class[] emptyClass = new Class[0]; 54 private static final Object[] emptyObject = new Object[0]; 55 56 private static final Logger logger = Util.getClassLogger(); 57 58 /** 59 * Cache from a class to its default constructor. 60 * 61 * To avoid synchronization among threads, we use {@link ThreadLocal}. 62 */ 63 private static final ThreadLocal<Map<Class, WeakReference<Constructor>>> tls = new ThreadLocal<Map<Class,WeakReference<Constructor>>>() { 64 @Override 65 public Map<Class,WeakReference<Constructor>> initialValue() { 66 return new WeakHashMap<Class,WeakReference<Constructor>>(); 67 } 68 }; 69 70 public static void cleanCache() { 71 if (tls != null) { 72 try { 73 tls.remove(); 74 } catch (Exception e) { 75 logger.log(Level.WARNING, "Unable to clean Thread Local cache of classes used in Unmarshaller: {0}", e.getLocalizedMessage()); 76 } 77 } 78 } 79 80 /** 81 * Creates a new instance of the class but throw exceptions without catching it. 82 */ 83 public static <T> T create0( final Class<T> clazz ) throws IllegalAccessException, InvocationTargetException, InstantiationException { 84 Map<Class,WeakReference<Constructor>> m = tls.get(); 85 Constructor<T> cons = null; 86 WeakReference<Constructor> consRef = m.get(clazz); 87 if(consRef!=null) 88 cons = consRef.get(); 89 if(cons==null) { 90 if (System.getSecurityManager() == null) { 91 cons = tryGetDeclaredConstructor(clazz); 92 } else { 93 cons = AccessController.doPrivileged(new PrivilegedAction<Constructor<T>>() { 94 @Override 95 public Constructor<T> run() { 96 return tryGetDeclaredConstructor(clazz); 97 } 98 }); 99 } 100 101 int classMod = clazz.getModifiers(); 102 103 if(!Modifier.isPublic(classMod) || !Modifier.isPublic(cons.getModifiers())) { 104 // attempt to make it work even if the constructor is not accessible 105 try { 106 cons.setAccessible(true); 107 } catch(SecurityException e) { 108 // but if we don't have a permission to do so, work gracefully. 109 logger.log(Level.FINE,"Unable to make the constructor of "+clazz+" accessible",e); 110 throw e; 111 } 112 } 113 114 m.put(clazz,new WeakReference<Constructor>(cons)); 115 } 116 117 return cons.newInstance(emptyObject); 118 } 119 120 private static <T> Constructor<T> tryGetDeclaredConstructor(Class<T> clazz) { 121 try { 122 return clazz.getDeclaredConstructor((Class<T>[])emptyClass); 123 } catch (NoSuchMethodException e) { 124 logger.log(Level.INFO,"No default constructor found on "+clazz,e); 125 NoSuchMethodError exp; 126 if(clazz.getDeclaringClass()!=null && !Modifier.isStatic(clazz.getModifiers())) { 127 exp = new NoSuchMethodError(Messages.NO_DEFAULT_CONSTRUCTOR_IN_INNER_CLASS 128 .format(clazz.getName())); 129 } else { 130 exp = new NoSuchMethodError(e.getMessage()); 131 } 132 exp.initCause(e); 133 throw exp; 134 } 135 } 136 137 /** 138 * The same as {@link #create0} but with an error handling to make 139 * the instantiation error fatal. 140 */ 141 public static <T> T create( Class<T> clazz ) { 142 try { 143 return create0(clazz); 144 } catch (InstantiationException e) { 145 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e); 146 throw new InstantiationError(e.toString()); 147 } catch (IllegalAccessException e) { 148 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e); 149 throw new IllegalAccessError(e.toString()); 150 } catch (InvocationTargetException e) { 151 Throwable target = e.getTargetException(); 152 153 // most likely an error on the user's code. 154 // just let it through for the ease of debugging 155 if(target instanceof RuntimeException) 156 throw (RuntimeException)target; 157 158 // error. just forward it for the ease of debugging 159 if(target instanceof Error) 160 throw (Error)target; 161 162 // a checked exception. 163 // not sure how we should report this error, 164 // but for now we just forward it by wrapping it into a runtime exception 165 throw new IllegalStateException(target); 166 } 167 } 168 169 /** 170 * Call a method in the factory class to get the object. 171 */ 172 public static Object create(Method method) { 173 Throwable errorMsg; 174 try { 175 return method.invoke(null, emptyObject); 176 } catch (InvocationTargetException ive) { 177 Throwable target = ive.getTargetException(); 178 179 if(target instanceof RuntimeException) 180 throw (RuntimeException)target; 181 182 if(target instanceof Error) 183 throw (Error)target; 184 185 throw new IllegalStateException(target); 186 } catch (IllegalAccessException e) { 187 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),e); 188 throw new IllegalAccessError(e.toString()); 189 } catch (IllegalArgumentException iae){ 190 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),iae); 191 errorMsg = iae; 192 } catch (NullPointerException npe){ 193 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),npe); 194 errorMsg = npe; 195 } catch (ExceptionInInitializerError eie){ 196 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),eie); 197 errorMsg = eie; 198 } 199 200 NoSuchMethodError exp; 201 exp = new NoSuchMethodError(errorMsg.getMessage()); 202 exp.initCause(errorMsg); 203 throw exp; 204 } 205 206 /** 207 * Infers the instanciable implementation class that can be assigned to the given field type. 208 * 209 * @return null 210 * if inference fails. 211 */ 212 public static <T> Class<? extends T> inferImplClass(Class<T> fieldType, Class[] knownImplClasses) { 213 if(!fieldType.isInterface()) 214 return fieldType; 215 216 for( Class<?> impl : knownImplClasses ) { 217 if(fieldType.isAssignableFrom(impl)) 218 return impl.asSubclass(fieldType); 219 } 220 221 // if we can't find an implementation class, 222 // let's just hope that we will never need to create a new object, 223 // and returns null 224 return null; 225 } 226 }