1
10
11 package com.sun.xml.bind.v2;
12
13 import java.lang.reflect.Constructor;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Modifier;
17 import java.lang.ref.WeakReference;
18 import java.security.AccessController;
19 import java.security.PrivilegedAction;
20 import java.util.Map;
21 import java.util.WeakHashMap;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
24
25 import com.sun.xml.bind.Utils;
26
27
37 public final class ClassFactory {
38 private static final Class[] emptyClass = new Class[0];
39 private static final Object[] emptyObject = new Object[0];
40
41 private static final Logger logger = Utils.getClassLogger();
42
43
48 private static final ThreadLocal<Map<Class, WeakReference<Constructor>>> tls = new ThreadLocal<Map<Class,WeakReference<Constructor>>>() {
49 @Override
50 public Map<Class,WeakReference<Constructor>> initialValue() {
51 return new WeakHashMap<Class,WeakReference<Constructor>>();
52 }
53 };
54
55 public static void cleanCache() {
56 if (tls != null) {
57 try {
58 tls.remove();
59 } catch (Exception e) {
60 logger.log(Level.WARNING, "Unable to clean Thread Local cache of classes used in Unmarshaller: {0}", e.getLocalizedMessage());
61 }
62 }
63 }
64
65
68 public static <T> T create0( final Class<T> clazz ) throws IllegalAccessException, InvocationTargetException, InstantiationException {
69 Map<Class,WeakReference<Constructor>> m = tls.get();
70 Constructor<T> cons = null;
71 WeakReference<Constructor> consRef = m.get(clazz);
72 if(consRef!=null)
73 cons = consRef.get();
74 if(cons==null) {
75 if (System.getSecurityManager() == null) {
76 cons = tryGetDeclaredConstructor(clazz);
77 } else {
78 cons = AccessController.doPrivileged(new PrivilegedAction<Constructor<T>>() {
79 @Override
80 public Constructor<T> run() {
81 return tryGetDeclaredConstructor(clazz);
82 }
83 });
84 }
85
86 int classMod = clazz.getModifiers();
87
88 if(!Modifier.isPublic(classMod) || !Modifier.isPublic(cons.getModifiers())) {
89
90 try {
91 cons.setAccessible(true);
92 } catch(SecurityException e) {
93
94 logger.log(Level.FINE,"Unable to make the constructor of "+clazz+" accessible",e);
95 throw e;
96 }
97 }
98
99 m.put(clazz,new WeakReference<Constructor>(cons));
100 }
101
102 return cons.newInstance(emptyObject);
103 }
104
105 private static <T> Constructor<T> tryGetDeclaredConstructor(Class<T> clazz) {
106 try {
107 return clazz.getDeclaredConstructor((Class<T>[])emptyClass);
108 } catch (NoSuchMethodException e) {
109 logger.log(Level.INFO,"No default constructor found on "+clazz,e);
110 NoSuchMethodError exp;
111 if(clazz.getDeclaringClass()!=null && !Modifier.isStatic(clazz.getModifiers())) {
112 exp = new NoSuchMethodError(Messages.NO_DEFAULT_CONSTRUCTOR_IN_INNER_CLASS
113 .format(clazz.getName()));
114 } else {
115 exp = new NoSuchMethodError(e.getMessage());
116 }
117 exp.initCause(e);
118 throw exp;
119 }
120 }
121
122
126 public static <T> T create( Class<T> clazz ) {
127 try {
128 return create0(clazz);
129 } catch (InstantiationException e) {
130 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e);
131 throw new InstantiationError(e.toString());
132 } catch (IllegalAccessException e) {
133 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e);
134 throw new IllegalAccessError(e.toString());
135 } catch (InvocationTargetException e) {
136 Throwable target = e.getTargetException();
137
138
139
140 if(target instanceof RuntimeException)
141 throw (RuntimeException)target;
142
143
144 if(target instanceof Error)
145 throw (Error)target;
146
147
148
149
150 throw new IllegalStateException(target);
151 }
152 }
153
154
157 public static Object create(Method method) {
158 Throwable errorMsg;
159 try {
160 return method.invoke(null, emptyObject);
161 } catch (InvocationTargetException ive) {
162 Throwable target = ive.getTargetException();
163
164 if(target instanceof RuntimeException)
165 throw (RuntimeException)target;
166
167 if(target instanceof Error)
168 throw (Error)target;
169
170 throw new IllegalStateException(target);
171 } catch (IllegalAccessException e) {
172 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),e);
173 throw new IllegalAccessError(e.toString());
174 } catch (IllegalArgumentException iae){
175 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),iae);
176 errorMsg = iae;
177 } catch (NullPointerException npe){
178 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),npe);
179 errorMsg = npe;
180 } catch (ExceptionInInitializerError eie){
181 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),eie);
182 errorMsg = eie;
183 }
184
185 NoSuchMethodError exp;
186 exp = new NoSuchMethodError(errorMsg.getMessage());
187 exp.initCause(errorMsg);
188 throw exp;
189 }
190
191
197 public static <T> Class<? extends T> inferImplClass(Class<T> fieldType, Class[] knownImplClasses) {
198 if(!fieldType.isInterface())
199 return fieldType;
200
201 for( Class<?> impl : knownImplClasses ) {
202 if(fieldType.isAssignableFrom(impl))
203 return impl.asSubclass(fieldType);
204 }
205
206
207
208
209 return null;
210 }
211 }
212