src/share/jaxws_classes/com/sun/xml/internal/bind/v2/ClassFactory.java

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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.util.Map;
34 import java.util.WeakHashMap;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37
38 import com.sun.xml.internal.bind.Util;
39
40 /**
41 * Creates new instances of classes.
42 *
43 * <p>
44 * This code handles the case where the class is not public or the constructor is
45 * not public.
46 *
47 * @since 2.0
48 * @author Kohsuke Kawaguchi
49 */
50 public final class ClassFactory {
51 private static final Class[] emptyClass = new Class[0];
52 private static final Object[] emptyObject = new Object[0];
53
54 private static final Logger logger = Util.getClassLogger();
55
56 /**
57 * Cache from a class to its default constructor.
58 *
59 * To avoid synchronization among threads, we use {@link ThreadLocal}.
60 */
61 private static final ThreadLocal<Map<Class, WeakReference<Constructor>>> tls = new ThreadLocal<Map<Class,WeakReference<Constructor>>>() {
62 @Override
63 public Map<Class,WeakReference<Constructor>> initialValue() {
64 return new WeakHashMap<Class,WeakReference<Constructor>>();
65 }
66 };
67
68 public static void cleanCache() {
69 if (tls != null) {
70 try {
71 tls.remove();
72 } catch (Exception e) {
73 logger.log(Level.WARNING, "Unable to clean Thread Local cache of classes used in Unmarshaller: {0}", e.getLocalizedMessage());
74 }
75 }
76 }
77
78 /**
79 * Creates a new instance of the class but throw exceptions without catching it.
80 */
81 public static <T> T create0( final Class<T> clazz ) throws IllegalAccessException, InvocationTargetException, InstantiationException {
82 Map<Class,WeakReference<Constructor>> m = tls.get();
83 Constructor<T> cons = null;
84 WeakReference<Constructor> consRef = m.get(clazz);
85 if(consRef!=null)
86 cons = consRef.get();
87 if(cons==null) {
88 try {
89 cons = clazz.getDeclaredConstructor(emptyClass);
90 } catch (NoSuchMethodException e) {
91 logger.log(Level.INFO,"No default constructor found on "+clazz,e);
92 NoSuchMethodError exp;
93 if(clazz.getDeclaringClass()!=null && !Modifier.isStatic(clazz.getModifiers())) {
94 exp = new NoSuchMethodError(Messages.NO_DEFAULT_CONSTRUCTOR_IN_INNER_CLASS.format(clazz.getName()));
95 } else {
96 exp = new NoSuchMethodError(e.getMessage());
97 }
98 exp.initCause(e);
99 throw exp;
100 }
101
102 int classMod = clazz.getModifiers();
103
104 if(!Modifier.isPublic(classMod) || !Modifier.isPublic(cons.getModifiers())) {
105 // attempt to make it work even if the constructor is not accessible
106 try {
107 cons.setAccessible(true);
108 } catch(SecurityException e) {
109 // but if we don't have a permission to do so, work gracefully.
110 logger.log(Level.FINE,"Unable to make the constructor of "+clazz+" accessible",e);
111 throw e;
112 }
113 }
114
115 m.put(clazz,new WeakReference<Constructor>(cons));
116 }
117
118 return cons.newInstance(emptyObject);
119 }
120
121 /**
122 * The same as {@link #create0} but with an error handling to make
123 * the instantiation error fatal.
124 */
125 public static <T> T create( Class<T> clazz ) {
126 try {
127 return create0(clazz);
128 } catch (InstantiationException e) {
129 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e);
130 throw new InstantiationError(e.toString());
131 } catch (IllegalAccessException e) {
132 logger.log(Level.INFO,"failed to create a new instance of "+clazz,e);
133 throw new IllegalAccessError(e.toString());
134 } catch (InvocationTargetException e) {
135 Throwable target = e.getTargetException();
136
137 // most likely an error on the user's code.
138 // just let it through for the ease of debugging
139 if(target instanceof RuntimeException)
140 throw (RuntimeException)target;
141
142 // error. just forward it for the ease of debugging
143 if(target instanceof Error)
144 throw (Error)target;
145
146 // a checked exception.
147 // not sure how we should report this error,
148 // but for now we just forward it by wrapping it into a runtime exception
149 throw new IllegalStateException(target);
150 }
151 }
152
153 /**
154 * Call a method in the factory class to get the object.
155 */
156 public static Object create(Method method) {
157 Throwable errorMsg;
158 try {
159 return method.invoke(null, emptyObject);
160 } catch (InvocationTargetException ive) {
161 Throwable target = ive.getTargetException();
162
163 if(target instanceof RuntimeException)
164 throw (RuntimeException)target;
165
166 if(target instanceof Error)
167 throw (Error)target;
168
169 throw new IllegalStateException(target);
170 } catch (IllegalAccessException e) {
171 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),e);
172 throw new IllegalAccessError(e.toString());
173 } catch (IllegalArgumentException iae){
174 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),iae);
175 errorMsg = iae;
176 } catch (NullPointerException npe){
177 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),npe);
178 errorMsg = npe;
179 } catch (ExceptionInInitializerError eie){
180 logger.log(Level.INFO,"failed to create a new instance of "+method.getReturnType().getName(),eie);
181 errorMsg = eie;
182 }
183
184 NoSuchMethodError exp;
185 exp = new NoSuchMethodError(errorMsg.getMessage());
186 exp.initCause(errorMsg);
187 throw exp;
188 }
189
190 /**
191 * Infers the instanciable implementation class that can be assigned to the given field type.
192 *
193 * @return null
194 * if inference fails.
195 */
196 public static <T> Class<? extends T> inferImplClass(Class<T> fieldType, Class[] knownImplClasses) {
197 if(!fieldType.isInterface())
198 return fieldType;
199
200 for( Class<?> impl : knownImplClasses ) {
201 if(fieldType.isAssignableFrom(impl))
202 return impl.asSubclass(fieldType);
203 }
204
205 // if we can't find an implementation class,
206 // let's just hope that we will never need to create a new object,
207 // and returns null
208 return null;
209 }
210 }

mercurial