author | chegar |
Fri, 15 Apr 2016 16:19:15 +0100 | |
changeset 37363 | 329dba26ffd2 |
parent 34357 | 231fdaed751a |
child 40410 | 5fd4a1f809f8 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
34357
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
2 |
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
package java.io; |
|
27 |
||
28 |
import java.lang.ref.Reference; |
|
29 |
import java.lang.ref.ReferenceQueue; |
|
30 |
import java.lang.ref.SoftReference; |
|
31 |
import java.lang.ref.WeakReference; |
|
32 |
import java.lang.reflect.Constructor; |
|
33 |
import java.lang.reflect.Field; |
|
34 |
import java.lang.reflect.InvocationTargetException; |
|
35 |
import java.lang.reflect.Member; |
|
36 |
import java.lang.reflect.Method; |
|
37 |
import java.lang.reflect.Modifier; |
|
38 |
import java.lang.reflect.Proxy; |
|
39 |
import java.security.AccessController; |
|
40 |
import java.security.MessageDigest; |
|
41 |
import java.security.NoSuchAlgorithmException; |
|
42 |
import java.security.PrivilegedAction; |
|
43 |
import java.util.ArrayList; |
|
44 |
import java.util.Arrays; |
|
45 |
import java.util.Collections; |
|
46 |
import java.util.Comparator; |
|
47 |
import java.util.HashSet; |
|
48 |
import java.util.Set; |
|
49 |
import java.util.concurrent.ConcurrentHashMap; |
|
50 |
import java.util.concurrent.ConcurrentMap; |
|
33674
566777f73c32
8140606: Update library code to use internal Unsafe
chegar
parents:
33302
diff
changeset
|
51 |
import jdk.internal.misc.Unsafe; |
37363
329dba26ffd2
8137058: Clear out all non-Critical APIs from sun.reflect
chegar
parents:
34357
diff
changeset
|
52 |
import jdk.internal.reflect.CallerSensitive; |
329dba26ffd2
8137058: Clear out all non-Critical APIs from sun.reflect
chegar
parents:
34357
diff
changeset
|
53 |
import jdk.internal.reflect.Reflection; |
329dba26ffd2
8137058: Clear out all non-Critical APIs from sun.reflect
chegar
parents:
34357
diff
changeset
|
54 |
import jdk.internal.reflect.ReflectionFactory; |
18237 | 55 |
import sun.reflect.misc.ReflectUtil; |
2 | 56 |
|
34357
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
57 |
import static java.io.ObjectStreamField.*; |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
58 |
|
2 | 59 |
/** |
60 |
* Serialization's descriptor for classes. It contains the name and |
|
61 |
* serialVersionUID of the class. The ObjectStreamClass for a specific class |
|
62 |
* loaded in this Java VM can be found/created using the lookup method. |
|
63 |
* |
|
64 |
* <p>The algorithm to compute the SerialVersionUID is described in |
|
65 |
* <a href="../../../platform/serialization/spec/class.html#4100">Object |
|
66 |
* Serialization Specification, Section 4.6, Stream Unique Identifiers</a>. |
|
67 |
* |
|
68 |
* @author Mike Warres |
|
69 |
* @author Roger Riggs |
|
70 |
* @see ObjectStreamField |
|
71 |
* @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a> |
|
24865
09b1d992ca72
8044740: Convert all JDK versions used in @since tag to 1.n[.n] in jdk repo
henryjen
parents:
22936
diff
changeset
|
72 |
* @since 1.1 |
2 | 73 |
*/ |
74 |
public class ObjectStreamClass implements Serializable { |
|
75 |
||
76 |
/** serialPersistentFields value indicating no serializable fields */ |
|
77 |
public static final ObjectStreamField[] NO_FIELDS = |
|
78 |
new ObjectStreamField[0]; |
|
79 |
||
80 |
private static final long serialVersionUID = -6120832682080437368L; |
|
81 |
private static final ObjectStreamField[] serialPersistentFields = |
|
82 |
NO_FIELDS; |
|
83 |
||
84 |
/** reflection factory for obtaining serialization constructors */ |
|
51 | 85 |
private static final ReflectionFactory reflFactory = |
2 | 86 |
AccessController.doPrivileged( |
87 |
new ReflectionFactory.GetReflectionFactoryAction()); |
|
88 |
||
89 |
private static class Caches { |
|
90 |
/** cache mapping local classes -> descriptors */ |
|
91 |
static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs = |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
92 |
new ConcurrentHashMap<>(); |
2 | 93 |
|
94 |
/** cache mapping field group/local desc pairs -> field reflectors */ |
|
95 |
static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors = |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
96 |
new ConcurrentHashMap<>(); |
2 | 97 |
|
98 |
/** queue for WeakReferences to local classes */ |
|
99 |
private static final ReferenceQueue<Class<?>> localDescsQueue = |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
100 |
new ReferenceQueue<>(); |
2 | 101 |
/** queue for WeakReferences to field reflectors keys */ |
102 |
private static final ReferenceQueue<Class<?>> reflectorsQueue = |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
103 |
new ReferenceQueue<>(); |
2 | 104 |
} |
105 |
||
106 |
/** class associated with this descriptor (if any) */ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
107 |
private Class<?> cl; |
2 | 108 |
/** name of class represented by this descriptor */ |
109 |
private String name; |
|
110 |
/** serialVersionUID of represented class (null if not computed yet) */ |
|
111 |
private volatile Long suid; |
|
112 |
||
113 |
/** true if represents dynamic proxy class */ |
|
114 |
private boolean isProxy; |
|
115 |
/** true if represents enum type */ |
|
116 |
private boolean isEnum; |
|
117 |
/** true if represented class implements Serializable */ |
|
118 |
private boolean serializable; |
|
119 |
/** true if represented class implements Externalizable */ |
|
120 |
private boolean externalizable; |
|
121 |
/** true if desc has data written by class-defined writeObject method */ |
|
122 |
private boolean hasWriteObjectData; |
|
123 |
/** |
|
124 |
* true if desc has externalizable data written in block data format; this |
|
125 |
* must be true by default to accommodate ObjectInputStream subclasses which |
|
126 |
* override readClassDescriptor() to return class descriptors obtained from |
|
127 |
* ObjectStreamClass.lookup() (see 4461737) |
|
128 |
*/ |
|
129 |
private boolean hasBlockExternalData = true; |
|
130 |
||
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
131 |
/** |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
132 |
* Contains information about InvalidClassException instances to be thrown |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
133 |
* when attempting operations on an invalid class. Note that instances of |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
134 |
* this class are immutable and are potentially shared among |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
135 |
* ObjectStreamClass instances. |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
136 |
*/ |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
137 |
private static class ExceptionInfo { |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
138 |
private final String className; |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
139 |
private final String message; |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
140 |
|
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
141 |
ExceptionInfo(String cn, String msg) { |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
142 |
className = cn; |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
143 |
message = msg; |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
144 |
} |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
145 |
|
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
146 |
/** |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
147 |
* Returns (does not throw) an InvalidClassException instance created |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
148 |
* from the information in this object, suitable for being thrown by |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
149 |
* the caller. |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
150 |
*/ |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
151 |
InvalidClassException newInvalidClassException() { |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
152 |
return new InvalidClassException(className, message); |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
153 |
} |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
154 |
} |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
155 |
|
2 | 156 |
/** exception (if any) thrown while attempting to resolve class */ |
157 |
private ClassNotFoundException resolveEx; |
|
158 |
/** exception (if any) to throw if non-enum deserialization attempted */ |
|
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
159 |
private ExceptionInfo deserializeEx; |
2 | 160 |
/** exception (if any) to throw if non-enum serialization attempted */ |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
161 |
private ExceptionInfo serializeEx; |
2 | 162 |
/** exception (if any) to throw if default serialization attempted */ |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
163 |
private ExceptionInfo defaultSerializeEx; |
2 | 164 |
|
165 |
/** serializable fields */ |
|
166 |
private ObjectStreamField[] fields; |
|
167 |
/** aggregate marshalled size of primitive fields */ |
|
168 |
private int primDataSize; |
|
169 |
/** number of non-primitive fields */ |
|
170 |
private int numObjFields; |
|
171 |
/** reflector for setting/getting serializable field values */ |
|
172 |
private FieldReflector fieldRefl; |
|
173 |
/** data layout of serialized objects described by this class desc */ |
|
174 |
private volatile ClassDataSlot[] dataLayout; |
|
175 |
||
176 |
/** serialization-appropriate constructor, or null if none */ |
|
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
177 |
private Constructor<?> cons; |
2 | 178 |
/** class-defined writeObject method, or null if none */ |
179 |
private Method writeObjectMethod; |
|
180 |
/** class-defined readObject method, or null if none */ |
|
181 |
private Method readObjectMethod; |
|
182 |
/** class-defined readObjectNoData method, or null if none */ |
|
183 |
private Method readObjectNoDataMethod; |
|
184 |
/** class-defined writeReplace method, or null if none */ |
|
185 |
private Method writeReplaceMethod; |
|
186 |
/** class-defined readResolve method, or null if none */ |
|
187 |
private Method readResolveMethod; |
|
188 |
||
189 |
/** local class descriptor for represented class (may point to self) */ |
|
190 |
private ObjectStreamClass localDesc; |
|
191 |
/** superclass descriptor appearing in stream */ |
|
192 |
private ObjectStreamClass superDesc; |
|
193 |
||
33289 | 194 |
/** true if, and only if, the object has been correctly initialized */ |
195 |
private boolean initialized; |
|
196 |
||
2 | 197 |
/** |
198 |
* Initializes native code. |
|
199 |
*/ |
|
200 |
private static native void initNative(); |
|
201 |
static { |
|
202 |
initNative(); |
|
203 |
} |
|
204 |
||
205 |
/** |
|
206 |
* Find the descriptor for a class that can be serialized. Creates an |
|
207 |
* ObjectStreamClass instance if one does not exist yet for class. Null is |
|
208 |
* returned if the specified class does not implement java.io.Serializable |
|
209 |
* or java.io.Externalizable. |
|
210 |
* |
|
211 |
* @param cl class for which to get the descriptor |
|
212 |
* @return the class descriptor for the specified class |
|
213 |
*/ |
|
214 |
public static ObjectStreamClass lookup(Class<?> cl) { |
|
215 |
return lookup(cl, false); |
|
216 |
} |
|
217 |
||
218 |
/** |
|
219 |
* Returns the descriptor for any class, regardless of whether it |
|
220 |
* implements {@link Serializable}. |
|
221 |
* |
|
222 |
* @param cl class for which to get the descriptor |
|
223 |
* @return the class descriptor for the specified class |
|
224 |
* @since 1.6 |
|
225 |
*/ |
|
226 |
public static ObjectStreamClass lookupAny(Class<?> cl) { |
|
227 |
return lookup(cl, true); |
|
228 |
} |
|
229 |
||
230 |
/** |
|
231 |
* Returns the name of the class described by this descriptor. |
|
232 |
* This method returns the name of the class in the format that |
|
233 |
* is used by the {@link Class#getName} method. |
|
234 |
* |
|
235 |
* @return a string representing the name of the class |
|
236 |
*/ |
|
237 |
public String getName() { |
|
238 |
return name; |
|
239 |
} |
|
240 |
||
241 |
/** |
|
242 |
* Return the serialVersionUID for this class. The serialVersionUID |
|
243 |
* defines a set of classes all with the same name that have evolved from a |
|
244 |
* common root class and agree to be serialized and deserialized using a |
|
245 |
* common format. NonSerializable classes have a serialVersionUID of 0L. |
|
246 |
* |
|
247 |
* @return the SUID of the class described by this descriptor |
|
248 |
*/ |
|
249 |
public long getSerialVersionUID() { |
|
250 |
// REMIND: synchronize instead of relying on volatile? |
|
251 |
if (suid == null) { |
|
51 | 252 |
suid = AccessController.doPrivileged( |
253 |
new PrivilegedAction<Long>() { |
|
254 |
public Long run() { |
|
255 |
return computeDefaultSUID(cl); |
|
2 | 256 |
} |
257 |
} |
|
258 |
); |
|
259 |
} |
|
260 |
return suid.longValue(); |
|
261 |
} |
|
262 |
||
263 |
/** |
|
264 |
* Return the class in the local VM that this version is mapped to. Null |
|
265 |
* is returned if there is no corresponding local class. |
|
266 |
* |
|
267 |
* @return the <code>Class</code> instance that this descriptor represents |
|
268 |
*/ |
|
18238
d1ed51b53296
8012917: ObjectStreamClass and ObjectStreamField should be CallerSensitive aware
chegar
parents:
18237
diff
changeset
|
269 |
@CallerSensitive |
2 | 270 |
public Class<?> forClass() { |
18237 | 271 |
if (cl == null) { |
272 |
return null; |
|
273 |
} |
|
33289 | 274 |
requireInitialized(); |
18260
7ef05ae0bd19
8012243: about 30% regression on specjvm2008.serial on 7u25 comparing 7u21
dfuchs
parents:
18238
diff
changeset
|
275 |
if (System.getSecurityManager() != null) { |
7ef05ae0bd19
8012243: about 30% regression on specjvm2008.serial on 7u25 comparing 7u21
dfuchs
parents:
18238
diff
changeset
|
276 |
Class<?> caller = Reflection.getCallerClass(); |
7ef05ae0bd19
8012243: about 30% regression on specjvm2008.serial on 7u25 comparing 7u21
dfuchs
parents:
18238
diff
changeset
|
277 |
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) { |
7ef05ae0bd19
8012243: about 30% regression on specjvm2008.serial on 7u25 comparing 7u21
dfuchs
parents:
18238
diff
changeset
|
278 |
ReflectUtil.checkPackageAccess(cl); |
7ef05ae0bd19
8012243: about 30% regression on specjvm2008.serial on 7u25 comparing 7u21
dfuchs
parents:
18238
diff
changeset
|
279 |
} |
18237 | 280 |
} |
2 | 281 |
return cl; |
282 |
} |
|
283 |
||
284 |
/** |
|
285 |
* Return an array of the fields of this serializable class. |
|
286 |
* |
|
287 |
* @return an array containing an element for each persistent field of |
|
288 |
* this class. Returns an array of length zero if there are no |
|
289 |
* fields. |
|
290 |
* @since 1.2 |
|
291 |
*/ |
|
292 |
public ObjectStreamField[] getFields() { |
|
293 |
return getFields(true); |
|
294 |
} |
|
295 |
||
296 |
/** |
|
297 |
* Get the field of this class by name. |
|
298 |
* |
|
299 |
* @param name the name of the data field to look for |
|
300 |
* @return The ObjectStreamField object of the named field or null if |
|
301 |
* there is no such named field. |
|
302 |
*/ |
|
303 |
public ObjectStreamField getField(String name) { |
|
304 |
return getField(name, null); |
|
305 |
} |
|
306 |
||
307 |
/** |
|
308 |
* Return a string describing this ObjectStreamClass. |
|
309 |
*/ |
|
310 |
public String toString() { |
|
311 |
return name + ": static final long serialVersionUID = " + |
|
312 |
getSerialVersionUID() + "L;"; |
|
313 |
} |
|
314 |
||
315 |
/** |
|
316 |
* Looks up and returns class descriptor for given class, or null if class |
|
317 |
* is non-serializable and "all" is set to false. |
|
318 |
* |
|
319 |
* @param cl class to look up |
|
320 |
* @param all if true, return descriptors for all classes; if false, only |
|
321 |
* return descriptors for serializable classes |
|
322 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
323 |
static ObjectStreamClass lookup(Class<?> cl, boolean all) { |
2 | 324 |
if (!(all || Serializable.class.isAssignableFrom(cl))) { |
325 |
return null; |
|
326 |
} |
|
327 |
processQueue(Caches.localDescsQueue, Caches.localDescs); |
|
328 |
WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); |
|
329 |
Reference<?> ref = Caches.localDescs.get(key); |
|
330 |
Object entry = null; |
|
331 |
if (ref != null) { |
|
332 |
entry = ref.get(); |
|
333 |
} |
|
334 |
EntryFuture future = null; |
|
335 |
if (entry == null) { |
|
336 |
EntryFuture newEntry = new EntryFuture(); |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
337 |
Reference<?> newRef = new SoftReference<>(newEntry); |
2 | 338 |
do { |
339 |
if (ref != null) { |
|
340 |
Caches.localDescs.remove(key, ref); |
|
341 |
} |
|
342 |
ref = Caches.localDescs.putIfAbsent(key, newRef); |
|
343 |
if (ref != null) { |
|
344 |
entry = ref.get(); |
|
345 |
} |
|
346 |
} while (ref != null && entry == null); |
|
347 |
if (entry == null) { |
|
348 |
future = newEntry; |
|
349 |
} |
|
350 |
} |
|
351 |
||
352 |
if (entry instanceof ObjectStreamClass) { // check common case first |
|
353 |
return (ObjectStreamClass) entry; |
|
354 |
} |
|
355 |
if (entry instanceof EntryFuture) { |
|
356 |
future = (EntryFuture) entry; |
|
357 |
if (future.getOwner() == Thread.currentThread()) { |
|
358 |
/* |
|
359 |
* Handle nested call situation described by 4803747: waiting |
|
360 |
* for future value to be set by a lookup() call further up the |
|
361 |
* stack will result in deadlock, so calculate and set the |
|
362 |
* future value here instead. |
|
363 |
*/ |
|
364 |
entry = null; |
|
365 |
} else { |
|
366 |
entry = future.get(); |
|
367 |
} |
|
368 |
} |
|
369 |
if (entry == null) { |
|
370 |
try { |
|
371 |
entry = new ObjectStreamClass(cl); |
|
372 |
} catch (Throwable th) { |
|
373 |
entry = th; |
|
374 |
} |
|
375 |
if (future.set(entry)) { |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
376 |
Caches.localDescs.put(key, new SoftReference<>(entry)); |
2 | 377 |
} else { |
378 |
// nested lookup call already set future |
|
379 |
entry = future.get(); |
|
380 |
} |
|
381 |
} |
|
382 |
||
383 |
if (entry instanceof ObjectStreamClass) { |
|
384 |
return (ObjectStreamClass) entry; |
|
385 |
} else if (entry instanceof RuntimeException) { |
|
386 |
throw (RuntimeException) entry; |
|
387 |
} else if (entry instanceof Error) { |
|
388 |
throw (Error) entry; |
|
389 |
} else { |
|
390 |
throw new InternalError("unexpected entry: " + entry); |
|
391 |
} |
|
392 |
} |
|
393 |
||
394 |
/** |
|
395 |
* Placeholder used in class descriptor and field reflector lookup tables |
|
396 |
* for an entry in the process of being initialized. (Internal) callers |
|
397 |
* which receive an EntryFuture belonging to another thread as the result |
|
398 |
* of a lookup should call the get() method of the EntryFuture; this will |
|
399 |
* return the actual entry once it is ready for use and has been set(). To |
|
400 |
* conserve objects, EntryFutures synchronize on themselves. |
|
401 |
*/ |
|
402 |
private static class EntryFuture { |
|
403 |
||
404 |
private static final Object unset = new Object(); |
|
405 |
private final Thread owner = Thread.currentThread(); |
|
406 |
private Object entry = unset; |
|
407 |
||
408 |
/** |
|
409 |
* Attempts to set the value contained by this EntryFuture. If the |
|
410 |
* EntryFuture's value has not been set already, then the value is |
|
411 |
* saved, any callers blocked in the get() method are notified, and |
|
412 |
* true is returned. If the value has already been set, then no saving |
|
413 |
* or notification occurs, and false is returned. |
|
414 |
*/ |
|
415 |
synchronized boolean set(Object entry) { |
|
416 |
if (this.entry != unset) { |
|
417 |
return false; |
|
418 |
} |
|
419 |
this.entry = entry; |
|
420 |
notifyAll(); |
|
421 |
return true; |
|
422 |
} |
|
423 |
||
424 |
/** |
|
425 |
* Returns the value contained by this EntryFuture, blocking if |
|
426 |
* necessary until a value is set. |
|
427 |
*/ |
|
428 |
synchronized Object get() { |
|
429 |
boolean interrupted = false; |
|
430 |
while (entry == unset) { |
|
431 |
try { |
|
432 |
wait(); |
|
433 |
} catch (InterruptedException ex) { |
|
434 |
interrupted = true; |
|
435 |
} |
|
436 |
} |
|
437 |
if (interrupted) { |
|
438 |
AccessController.doPrivileged( |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
439 |
new PrivilegedAction<>() { |
51 | 440 |
public Void run() { |
2 | 441 |
Thread.currentThread().interrupt(); |
442 |
return null; |
|
443 |
} |
|
444 |
} |
|
445 |
); |
|
446 |
} |
|
447 |
return entry; |
|
448 |
} |
|
449 |
||
450 |
/** |
|
451 |
* Returns the thread that created this EntryFuture. |
|
452 |
*/ |
|
453 |
Thread getOwner() { |
|
454 |
return owner; |
|
455 |
} |
|
456 |
} |
|
457 |
||
458 |
/** |
|
459 |
* Creates local class descriptor representing given class. |
|
460 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
461 |
private ObjectStreamClass(final Class<?> cl) { |
2 | 462 |
this.cl = cl; |
463 |
name = cl.getName(); |
|
464 |
isProxy = Proxy.isProxyClass(cl); |
|
465 |
isEnum = Enum.class.isAssignableFrom(cl); |
|
466 |
serializable = Serializable.class.isAssignableFrom(cl); |
|
467 |
externalizable = Externalizable.class.isAssignableFrom(cl); |
|
468 |
||
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
469 |
Class<?> superCl = cl.getSuperclass(); |
2 | 470 |
superDesc = (superCl != null) ? lookup(superCl, false) : null; |
471 |
localDesc = this; |
|
472 |
||
473 |
if (serializable) { |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
474 |
AccessController.doPrivileged(new PrivilegedAction<>() { |
51 | 475 |
public Void run() { |
2 | 476 |
if (isEnum) { |
477 |
suid = Long.valueOf(0); |
|
478 |
fields = NO_FIELDS; |
|
479 |
return null; |
|
480 |
} |
|
481 |
if (cl.isArray()) { |
|
482 |
fields = NO_FIELDS; |
|
483 |
return null; |
|
484 |
} |
|
485 |
||
486 |
suid = getDeclaredSUID(cl); |
|
487 |
try { |
|
488 |
fields = getSerialFields(cl); |
|
489 |
computeFieldOffsets(); |
|
490 |
} catch (InvalidClassException e) { |
|
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
491 |
serializeEx = deserializeEx = |
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
492 |
new ExceptionInfo(e.classname, e.getMessage()); |
2 | 493 |
fields = NO_FIELDS; |
494 |
} |
|
495 |
||
496 |
if (externalizable) { |
|
497 |
cons = getExternalizableConstructor(cl); |
|
498 |
} else { |
|
499 |
cons = getSerializableConstructor(cl); |
|
500 |
writeObjectMethod = getPrivateMethod(cl, "writeObject", |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
501 |
new Class<?>[] { ObjectOutputStream.class }, |
2 | 502 |
Void.TYPE); |
503 |
readObjectMethod = getPrivateMethod(cl, "readObject", |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
504 |
new Class<?>[] { ObjectInputStream.class }, |
2 | 505 |
Void.TYPE); |
506 |
readObjectNoDataMethod = getPrivateMethod( |
|
507 |
cl, "readObjectNoData", null, Void.TYPE); |
|
508 |
hasWriteObjectData = (writeObjectMethod != null); |
|
509 |
} |
|
510 |
writeReplaceMethod = getInheritableMethod( |
|
511 |
cl, "writeReplace", null, Object.class); |
|
512 |
readResolveMethod = getInheritableMethod( |
|
513 |
cl, "readResolve", null, Object.class); |
|
514 |
return null; |
|
515 |
} |
|
516 |
}); |
|
517 |
} else { |
|
518 |
suid = Long.valueOf(0); |
|
519 |
fields = NO_FIELDS; |
|
520 |
} |
|
521 |
||
522 |
try { |
|
523 |
fieldRefl = getReflector(fields, this); |
|
524 |
} catch (InvalidClassException ex) { |
|
525 |
// field mismatches impossible when matching local fields vs. self |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
526 |
throw new InternalError(ex); |
2 | 527 |
} |
528 |
||
529 |
if (deserializeEx == null) { |
|
530 |
if (isEnum) { |
|
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
531 |
deserializeEx = new ExceptionInfo(name, "enum type"); |
2 | 532 |
} else if (cons == null) { |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
533 |
deserializeEx = new ExceptionInfo(name, "no valid constructor"); |
2 | 534 |
} |
535 |
} |
|
536 |
for (int i = 0; i < fields.length; i++) { |
|
537 |
if (fields[i].getField() == null) { |
|
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
538 |
defaultSerializeEx = new ExceptionInfo( |
2 | 539 |
name, "unmatched serializable field(s) declared"); |
540 |
} |
|
541 |
} |
|
33289 | 542 |
initialized = true; |
2 | 543 |
} |
544 |
||
545 |
/** |
|
546 |
* Creates blank class descriptor which should be initialized via a |
|
547 |
* subsequent call to initProxy(), initNonProxy() or readNonProxy(). |
|
548 |
*/ |
|
549 |
ObjectStreamClass() { |
|
550 |
} |
|
551 |
||
552 |
/** |
|
553 |
* Initializes class descriptor representing a proxy class. |
|
554 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
555 |
void initProxy(Class<?> cl, |
2 | 556 |
ClassNotFoundException resolveEx, |
557 |
ObjectStreamClass superDesc) |
|
558 |
throws InvalidClassException |
|
559 |
{ |
|
33289 | 560 |
ObjectStreamClass osc = null; |
561 |
if (cl != null) { |
|
562 |
osc = lookup(cl, true); |
|
563 |
if (!osc.isProxy) { |
|
564 |
throw new InvalidClassException( |
|
565 |
"cannot bind proxy descriptor to a non-proxy class"); |
|
566 |
} |
|
567 |
} |
|
2 | 568 |
this.cl = cl; |
569 |
this.resolveEx = resolveEx; |
|
570 |
this.superDesc = superDesc; |
|
571 |
isProxy = true; |
|
572 |
serializable = true; |
|
573 |
suid = Long.valueOf(0); |
|
574 |
fields = NO_FIELDS; |
|
33289 | 575 |
if (osc != null) { |
576 |
localDesc = osc; |
|
2 | 577 |
name = localDesc.name; |
578 |
externalizable = localDesc.externalizable; |
|
579 |
writeReplaceMethod = localDesc.writeReplaceMethod; |
|
580 |
readResolveMethod = localDesc.readResolveMethod; |
|
581 |
deserializeEx = localDesc.deserializeEx; |
|
33289 | 582 |
cons = localDesc.cons; |
2 | 583 |
} |
584 |
fieldRefl = getReflector(fields, localDesc); |
|
33289 | 585 |
initialized = true; |
2 | 586 |
} |
587 |
||
588 |
/** |
|
589 |
* Initializes class descriptor representing a non-proxy class. |
|
590 |
*/ |
|
591 |
void initNonProxy(ObjectStreamClass model, |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
592 |
Class<?> cl, |
2 | 593 |
ClassNotFoundException resolveEx, |
594 |
ObjectStreamClass superDesc) |
|
595 |
throws InvalidClassException |
|
596 |
{ |
|
33289 | 597 |
long suid = Long.valueOf(model.getSerialVersionUID()); |
598 |
ObjectStreamClass osc = null; |
|
599 |
if (cl != null) { |
|
600 |
osc = lookup(cl, true); |
|
601 |
if (osc.isProxy) { |
|
602 |
throw new InvalidClassException( |
|
603 |
"cannot bind non-proxy descriptor to a proxy class"); |
|
604 |
} |
|
605 |
if (model.isEnum != osc.isEnum) { |
|
606 |
throw new InvalidClassException(model.isEnum ? |
|
607 |
"cannot bind enum descriptor to a non-enum class" : |
|
608 |
"cannot bind non-enum descriptor to an enum class"); |
|
609 |
} |
|
610 |
||
611 |
if (model.serializable == osc.serializable && |
|
612 |
!cl.isArray() && |
|
613 |
suid != osc.getSerialVersionUID()) { |
|
614 |
throw new InvalidClassException(osc.name, |
|
615 |
"local class incompatible: " + |
|
616 |
"stream classdesc serialVersionUID = " + suid + |
|
617 |
", local class serialVersionUID = " + |
|
618 |
osc.getSerialVersionUID()); |
|
619 |
} |
|
620 |
||
621 |
if (!classNamesEqual(model.name, osc.name)) { |
|
622 |
throw new InvalidClassException(osc.name, |
|
623 |
"local class name incompatible with stream class " + |
|
624 |
"name \"" + model.name + "\""); |
|
625 |
} |
|
626 |
||
627 |
if (!model.isEnum) { |
|
628 |
if ((model.serializable == osc.serializable) && |
|
629 |
(model.externalizable != osc.externalizable)) { |
|
630 |
throw new InvalidClassException(osc.name, |
|
631 |
"Serializable incompatible with Externalizable"); |
|
632 |
} |
|
633 |
||
634 |
if ((model.serializable != osc.serializable) || |
|
635 |
(model.externalizable != osc.externalizable) || |
|
636 |
!(model.serializable || model.externalizable)) { |
|
637 |
deserializeEx = new ExceptionInfo( |
|
638 |
osc.name, "class invalid for deserialization"); |
|
639 |
} |
|
640 |
} |
|
641 |
} |
|
642 |
||
2 | 643 |
this.cl = cl; |
644 |
this.resolveEx = resolveEx; |
|
645 |
this.superDesc = superDesc; |
|
646 |
name = model.name; |
|
33289 | 647 |
this.suid = suid; |
2 | 648 |
isProxy = false; |
649 |
isEnum = model.isEnum; |
|
650 |
serializable = model.serializable; |
|
651 |
externalizable = model.externalizable; |
|
652 |
hasBlockExternalData = model.hasBlockExternalData; |
|
653 |
hasWriteObjectData = model.hasWriteObjectData; |
|
654 |
fields = model.fields; |
|
655 |
primDataSize = model.primDataSize; |
|
656 |
numObjFields = model.numObjFields; |
|
657 |
||
33289 | 658 |
if (osc != null) { |
659 |
localDesc = osc; |
|
2 | 660 |
writeObjectMethod = localDesc.writeObjectMethod; |
661 |
readObjectMethod = localDesc.readObjectMethod; |
|
662 |
readObjectNoDataMethod = localDesc.readObjectNoDataMethod; |
|
663 |
writeReplaceMethod = localDesc.writeReplaceMethod; |
|
664 |
readResolveMethod = localDesc.readResolveMethod; |
|
665 |
if (deserializeEx == null) { |
|
666 |
deserializeEx = localDesc.deserializeEx; |
|
667 |
} |
|
33289 | 668 |
cons = localDesc.cons; |
2 | 669 |
} |
33289 | 670 |
|
2 | 671 |
fieldRefl = getReflector(fields, localDesc); |
672 |
// reassign to matched fields so as to reflect local unshared settings |
|
673 |
fields = fieldRefl.getFields(); |
|
33289 | 674 |
initialized = true; |
2 | 675 |
} |
676 |
||
677 |
/** |
|
678 |
* Reads non-proxy class descriptor information from given input stream. |
|
679 |
* The resulting class descriptor is not fully functional; it can only be |
|
680 |
* used as input to the ObjectInputStream.resolveClass() and |
|
681 |
* ObjectStreamClass.initNonProxy() methods. |
|
682 |
*/ |
|
683 |
void readNonProxy(ObjectInputStream in) |
|
684 |
throws IOException, ClassNotFoundException |
|
685 |
{ |
|
686 |
name = in.readUTF(); |
|
687 |
suid = Long.valueOf(in.readLong()); |
|
688 |
isProxy = false; |
|
689 |
||
690 |
byte flags = in.readByte(); |
|
691 |
hasWriteObjectData = |
|
692 |
((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); |
|
693 |
hasBlockExternalData = |
|
694 |
((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); |
|
695 |
externalizable = |
|
696 |
((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); |
|
697 |
boolean sflag = |
|
698 |
((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); |
|
699 |
if (externalizable && sflag) { |
|
700 |
throw new InvalidClassException( |
|
701 |
name, "serializable and externalizable flags conflict"); |
|
702 |
} |
|
703 |
serializable = externalizable || sflag; |
|
704 |
isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); |
|
705 |
if (isEnum && suid.longValue() != 0L) { |
|
706 |
throw new InvalidClassException(name, |
|
707 |
"enum descriptor has non-zero serialVersionUID: " + suid); |
|
708 |
} |
|
709 |
||
710 |
int numFields = in.readShort(); |
|
711 |
if (isEnum && numFields != 0) { |
|
712 |
throw new InvalidClassException(name, |
|
713 |
"enum descriptor has non-zero field count: " + numFields); |
|
714 |
} |
|
715 |
fields = (numFields > 0) ? |
|
716 |
new ObjectStreamField[numFields] : NO_FIELDS; |
|
717 |
for (int i = 0; i < numFields; i++) { |
|
718 |
char tcode = (char) in.readByte(); |
|
719 |
String fname = in.readUTF(); |
|
720 |
String signature = ((tcode == 'L') || (tcode == '[')) ? |
|
721 |
in.readTypeString() : new String(new char[] { tcode }); |
|
722 |
try { |
|
723 |
fields[i] = new ObjectStreamField(fname, signature, false); |
|
724 |
} catch (RuntimeException e) { |
|
725 |
throw (IOException) new InvalidClassException(name, |
|
726 |
"invalid descriptor for field " + fname).initCause(e); |
|
727 |
} |
|
728 |
} |
|
729 |
computeFieldOffsets(); |
|
730 |
} |
|
731 |
||
732 |
/** |
|
733 |
* Writes non-proxy class descriptor information to given output stream. |
|
734 |
*/ |
|
735 |
void writeNonProxy(ObjectOutputStream out) throws IOException { |
|
736 |
out.writeUTF(name); |
|
737 |
out.writeLong(getSerialVersionUID()); |
|
738 |
||
739 |
byte flags = 0; |
|
740 |
if (externalizable) { |
|
741 |
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; |
|
742 |
int protocol = out.getProtocolVersion(); |
|
743 |
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { |
|
744 |
flags |= ObjectStreamConstants.SC_BLOCK_DATA; |
|
745 |
} |
|
746 |
} else if (serializable) { |
|
747 |
flags |= ObjectStreamConstants.SC_SERIALIZABLE; |
|
748 |
} |
|
749 |
if (hasWriteObjectData) { |
|
750 |
flags |= ObjectStreamConstants.SC_WRITE_METHOD; |
|
751 |
} |
|
752 |
if (isEnum) { |
|
753 |
flags |= ObjectStreamConstants.SC_ENUM; |
|
754 |
} |
|
755 |
out.writeByte(flags); |
|
756 |
||
757 |
out.writeShort(fields.length); |
|
758 |
for (int i = 0; i < fields.length; i++) { |
|
759 |
ObjectStreamField f = fields[i]; |
|
760 |
out.writeByte(f.getTypeCode()); |
|
761 |
out.writeUTF(f.getName()); |
|
762 |
if (!f.isPrimitive()) { |
|
763 |
out.writeTypeString(f.getTypeString()); |
|
764 |
} |
|
765 |
} |
|
766 |
} |
|
767 |
||
768 |
/** |
|
769 |
* Returns ClassNotFoundException (if any) thrown while attempting to |
|
770 |
* resolve local class corresponding to this class descriptor. |
|
771 |
*/ |
|
772 |
ClassNotFoundException getResolveException() { |
|
773 |
return resolveEx; |
|
774 |
} |
|
775 |
||
776 |
/** |
|
33289 | 777 |
* Throws InternalError if not initialized. |
778 |
*/ |
|
779 |
private final void requireInitialized() { |
|
780 |
if (!initialized) |
|
781 |
throw new InternalError("Unexpected call when not initialized"); |
|
782 |
} |
|
783 |
||
784 |
/** |
|
2 | 785 |
* Throws an InvalidClassException if object instances referencing this |
786 |
* class descriptor should not be allowed to deserialize. This method does |
|
787 |
* not apply to deserialization of enum constants. |
|
788 |
*/ |
|
789 |
void checkDeserialize() throws InvalidClassException { |
|
33289 | 790 |
requireInitialized(); |
2 | 791 |
if (deserializeEx != null) { |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
792 |
throw deserializeEx.newInvalidClassException(); |
2 | 793 |
} |
794 |
} |
|
795 |
||
796 |
/** |
|
797 |
* Throws an InvalidClassException if objects whose class is represented by |
|
798 |
* this descriptor should not be allowed to serialize. This method does |
|
799 |
* not apply to serialization of enum constants. |
|
800 |
*/ |
|
801 |
void checkSerialize() throws InvalidClassException { |
|
33289 | 802 |
requireInitialized(); |
2 | 803 |
if (serializeEx != null) { |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
804 |
throw serializeEx.newInvalidClassException(); |
2 | 805 |
} |
806 |
} |
|
807 |
||
808 |
/** |
|
809 |
* Throws an InvalidClassException if objects whose class is represented by |
|
810 |
* this descriptor should not be permitted to use default serialization |
|
811 |
* (e.g., if the class declares serializable fields that do not correspond |
|
812 |
* to actual fields, and hence must use the GetField API). This method |
|
813 |
* does not apply to deserialization of enum constants. |
|
814 |
*/ |
|
815 |
void checkDefaultSerialize() throws InvalidClassException { |
|
33289 | 816 |
requireInitialized(); |
2 | 817 |
if (defaultSerializeEx != null) { |
11894
c7af6deeffd8
7110700: Enhance exception throwing mechanism in ObjectStreamClass
smarks
parents:
9035
diff
changeset
|
818 |
throw defaultSerializeEx.newInvalidClassException(); |
2 | 819 |
} |
820 |
} |
|
821 |
||
822 |
/** |
|
823 |
* Returns superclass descriptor. Note that on the receiving side, the |
|
824 |
* superclass descriptor may be bound to a class that is not a superclass |
|
825 |
* of the subclass descriptor's bound class. |
|
826 |
*/ |
|
827 |
ObjectStreamClass getSuperDesc() { |
|
33289 | 828 |
requireInitialized(); |
2 | 829 |
return superDesc; |
830 |
} |
|
831 |
||
832 |
/** |
|
833 |
* Returns the "local" class descriptor for the class associated with this |
|
834 |
* class descriptor (i.e., the result of |
|
835 |
* ObjectStreamClass.lookup(this.forClass())) or null if there is no class |
|
836 |
* associated with this descriptor. |
|
837 |
*/ |
|
838 |
ObjectStreamClass getLocalDesc() { |
|
33289 | 839 |
requireInitialized(); |
2 | 840 |
return localDesc; |
841 |
} |
|
842 |
||
843 |
/** |
|
844 |
* Returns arrays of ObjectStreamFields representing the serializable |
|
845 |
* fields of the represented class. If copy is true, a clone of this class |
|
846 |
* descriptor's field array is returned, otherwise the array itself is |
|
847 |
* returned. |
|
848 |
*/ |
|
849 |
ObjectStreamField[] getFields(boolean copy) { |
|
850 |
return copy ? fields.clone() : fields; |
|
851 |
} |
|
852 |
||
853 |
/** |
|
854 |
* Looks up a serializable field of the represented class by name and type. |
|
855 |
* A specified type of null matches all types, Object.class matches all |
|
856 |
* non-primitive types, and any other non-null type matches assignable |
|
857 |
* types only. Returns matching field, or null if no match found. |
|
858 |
*/ |
|
51 | 859 |
ObjectStreamField getField(String name, Class<?> type) { |
2 | 860 |
for (int i = 0; i < fields.length; i++) { |
861 |
ObjectStreamField f = fields[i]; |
|
862 |
if (f.getName().equals(name)) { |
|
863 |
if (type == null || |
|
864 |
(type == Object.class && !f.isPrimitive())) |
|
865 |
{ |
|
866 |
return f; |
|
867 |
} |
|
51 | 868 |
Class<?> ftype = f.getType(); |
2 | 869 |
if (ftype != null && type.isAssignableFrom(ftype)) { |
870 |
return f; |
|
871 |
} |
|
872 |
} |
|
873 |
} |
|
874 |
return null; |
|
875 |
} |
|
876 |
||
877 |
/** |
|
878 |
* Returns true if class descriptor represents a dynamic proxy class, false |
|
879 |
* otherwise. |
|
880 |
*/ |
|
881 |
boolean isProxy() { |
|
33289 | 882 |
requireInitialized(); |
2 | 883 |
return isProxy; |
884 |
} |
|
885 |
||
886 |
/** |
|
887 |
* Returns true if class descriptor represents an enum type, false |
|
888 |
* otherwise. |
|
889 |
*/ |
|
890 |
boolean isEnum() { |
|
33289 | 891 |
requireInitialized(); |
2 | 892 |
return isEnum; |
893 |
} |
|
894 |
||
895 |
/** |
|
896 |
* Returns true if represented class implements Externalizable, false |
|
897 |
* otherwise. |
|
898 |
*/ |
|
899 |
boolean isExternalizable() { |
|
33289 | 900 |
requireInitialized(); |
2 | 901 |
return externalizable; |
902 |
} |
|
903 |
||
904 |
/** |
|
905 |
* Returns true if represented class implements Serializable, false |
|
906 |
* otherwise. |
|
907 |
*/ |
|
908 |
boolean isSerializable() { |
|
33289 | 909 |
requireInitialized(); |
2 | 910 |
return serializable; |
911 |
} |
|
912 |
||
913 |
/** |
|
914 |
* Returns true if class descriptor represents externalizable class that |
|
915 |
* has written its data in 1.2 (block data) format, false otherwise. |
|
916 |
*/ |
|
917 |
boolean hasBlockExternalData() { |
|
33289 | 918 |
requireInitialized(); |
2 | 919 |
return hasBlockExternalData; |
920 |
} |
|
921 |
||
922 |
/** |
|
923 |
* Returns true if class descriptor represents serializable (but not |
|
924 |
* externalizable) class which has written its data via a custom |
|
925 |
* writeObject() method, false otherwise. |
|
926 |
*/ |
|
927 |
boolean hasWriteObjectData() { |
|
33289 | 928 |
requireInitialized(); |
2 | 929 |
return hasWriteObjectData; |
930 |
} |
|
931 |
||
932 |
/** |
|
933 |
* Returns true if represented class is serializable/externalizable and can |
|
934 |
* be instantiated by the serialization runtime--i.e., if it is |
|
935 |
* externalizable and defines a public no-arg constructor, or if it is |
|
936 |
* non-externalizable and its first non-serializable superclass defines an |
|
937 |
* accessible no-arg constructor. Otherwise, returns false. |
|
938 |
*/ |
|
939 |
boolean isInstantiable() { |
|
33289 | 940 |
requireInitialized(); |
2 | 941 |
return (cons != null); |
942 |
} |
|
943 |
||
944 |
/** |
|
945 |
* Returns true if represented class is serializable (but not |
|
946 |
* externalizable) and defines a conformant writeObject method. Otherwise, |
|
947 |
* returns false. |
|
948 |
*/ |
|
949 |
boolean hasWriteObjectMethod() { |
|
33289 | 950 |
requireInitialized(); |
2 | 951 |
return (writeObjectMethod != null); |
952 |
} |
|
953 |
||
954 |
/** |
|
955 |
* Returns true if represented class is serializable (but not |
|
956 |
* externalizable) and defines a conformant readObject method. Otherwise, |
|
957 |
* returns false. |
|
958 |
*/ |
|
959 |
boolean hasReadObjectMethod() { |
|
33289 | 960 |
requireInitialized(); |
2 | 961 |
return (readObjectMethod != null); |
962 |
} |
|
963 |
||
964 |
/** |
|
965 |
* Returns true if represented class is serializable (but not |
|
966 |
* externalizable) and defines a conformant readObjectNoData method. |
|
967 |
* Otherwise, returns false. |
|
968 |
*/ |
|
969 |
boolean hasReadObjectNoDataMethod() { |
|
33289 | 970 |
requireInitialized(); |
2 | 971 |
return (readObjectNoDataMethod != null); |
972 |
} |
|
973 |
||
974 |
/** |
|
975 |
* Returns true if represented class is serializable or externalizable and |
|
976 |
* defines a conformant writeReplace method. Otherwise, returns false. |
|
977 |
*/ |
|
978 |
boolean hasWriteReplaceMethod() { |
|
33289 | 979 |
requireInitialized(); |
2 | 980 |
return (writeReplaceMethod != null); |
981 |
} |
|
982 |
||
983 |
/** |
|
984 |
* Returns true if represented class is serializable or externalizable and |
|
985 |
* defines a conformant readResolve method. Otherwise, returns false. |
|
986 |
*/ |
|
987 |
boolean hasReadResolveMethod() { |
|
33289 | 988 |
requireInitialized(); |
2 | 989 |
return (readResolveMethod != null); |
990 |
} |
|
991 |
||
992 |
/** |
|
993 |
* Creates a new instance of the represented class. If the class is |
|
994 |
* externalizable, invokes its public no-arg constructor; otherwise, if the |
|
995 |
* class is serializable, invokes the no-arg constructor of the first |
|
996 |
* non-serializable superclass. Throws UnsupportedOperationException if |
|
997 |
* this class descriptor is not associated with a class, if the associated |
|
998 |
* class is non-serializable or if the appropriate no-arg constructor is |
|
999 |
* inaccessible/unavailable. |
|
1000 |
*/ |
|
1001 |
Object newInstance() |
|
1002 |
throws InstantiationException, InvocationTargetException, |
|
1003 |
UnsupportedOperationException |
|
1004 |
{ |
|
33289 | 1005 |
requireInitialized(); |
2 | 1006 |
if (cons != null) { |
1007 |
try { |
|
1008 |
return cons.newInstance(); |
|
1009 |
} catch (IllegalAccessException ex) { |
|
1010 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1011 |
throw new InternalError(ex); |
2 | 1012 |
} |
1013 |
} else { |
|
1014 |
throw new UnsupportedOperationException(); |
|
1015 |
} |
|
1016 |
} |
|
1017 |
||
1018 |
/** |
|
1019 |
* Invokes the writeObject method of the represented serializable class. |
|
1020 |
* Throws UnsupportedOperationException if this class descriptor is not |
|
1021 |
* associated with a class, or if the class is externalizable, |
|
1022 |
* non-serializable or does not define writeObject. |
|
1023 |
*/ |
|
1024 |
void invokeWriteObject(Object obj, ObjectOutputStream out) |
|
1025 |
throws IOException, UnsupportedOperationException |
|
1026 |
{ |
|
33289 | 1027 |
requireInitialized(); |
2 | 1028 |
if (writeObjectMethod != null) { |
1029 |
try { |
|
1030 |
writeObjectMethod.invoke(obj, new Object[]{ out }); |
|
1031 |
} catch (InvocationTargetException ex) { |
|
1032 |
Throwable th = ex.getTargetException(); |
|
1033 |
if (th instanceof IOException) { |
|
1034 |
throw (IOException) th; |
|
1035 |
} else { |
|
1036 |
throwMiscException(th); |
|
1037 |
} |
|
1038 |
} catch (IllegalAccessException ex) { |
|
1039 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1040 |
throw new InternalError(ex); |
2 | 1041 |
} |
1042 |
} else { |
|
1043 |
throw new UnsupportedOperationException(); |
|
1044 |
} |
|
1045 |
} |
|
1046 |
||
1047 |
/** |
|
1048 |
* Invokes the readObject method of the represented serializable class. |
|
1049 |
* Throws UnsupportedOperationException if this class descriptor is not |
|
1050 |
* associated with a class, or if the class is externalizable, |
|
1051 |
* non-serializable or does not define readObject. |
|
1052 |
*/ |
|
1053 |
void invokeReadObject(Object obj, ObjectInputStream in) |
|
1054 |
throws ClassNotFoundException, IOException, |
|
1055 |
UnsupportedOperationException |
|
1056 |
{ |
|
33289 | 1057 |
requireInitialized(); |
2 | 1058 |
if (readObjectMethod != null) { |
1059 |
try { |
|
1060 |
readObjectMethod.invoke(obj, new Object[]{ in }); |
|
1061 |
} catch (InvocationTargetException ex) { |
|
1062 |
Throwable th = ex.getTargetException(); |
|
1063 |
if (th instanceof ClassNotFoundException) { |
|
1064 |
throw (ClassNotFoundException) th; |
|
1065 |
} else if (th instanceof IOException) { |
|
1066 |
throw (IOException) th; |
|
1067 |
} else { |
|
1068 |
throwMiscException(th); |
|
1069 |
} |
|
1070 |
} catch (IllegalAccessException ex) { |
|
1071 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1072 |
throw new InternalError(ex); |
2 | 1073 |
} |
1074 |
} else { |
|
1075 |
throw new UnsupportedOperationException(); |
|
1076 |
} |
|
1077 |
} |
|
1078 |
||
1079 |
/** |
|
1080 |
* Invokes the readObjectNoData method of the represented serializable |
|
1081 |
* class. Throws UnsupportedOperationException if this class descriptor is |
|
1082 |
* not associated with a class, or if the class is externalizable, |
|
1083 |
* non-serializable or does not define readObjectNoData. |
|
1084 |
*/ |
|
1085 |
void invokeReadObjectNoData(Object obj) |
|
1086 |
throws IOException, UnsupportedOperationException |
|
1087 |
{ |
|
33289 | 1088 |
requireInitialized(); |
2 | 1089 |
if (readObjectNoDataMethod != null) { |
1090 |
try { |
|
1091 |
readObjectNoDataMethod.invoke(obj, (Object[]) null); |
|
1092 |
} catch (InvocationTargetException ex) { |
|
1093 |
Throwable th = ex.getTargetException(); |
|
1094 |
if (th instanceof ObjectStreamException) { |
|
1095 |
throw (ObjectStreamException) th; |
|
1096 |
} else { |
|
1097 |
throwMiscException(th); |
|
1098 |
} |
|
1099 |
} catch (IllegalAccessException ex) { |
|
1100 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1101 |
throw new InternalError(ex); |
2 | 1102 |
} |
1103 |
} else { |
|
1104 |
throw new UnsupportedOperationException(); |
|
1105 |
} |
|
1106 |
} |
|
1107 |
||
1108 |
/** |
|
1109 |
* Invokes the writeReplace method of the represented serializable class and |
|
1110 |
* returns the result. Throws UnsupportedOperationException if this class |
|
1111 |
* descriptor is not associated with a class, or if the class is |
|
1112 |
* non-serializable or does not define writeReplace. |
|
1113 |
*/ |
|
1114 |
Object invokeWriteReplace(Object obj) |
|
1115 |
throws IOException, UnsupportedOperationException |
|
1116 |
{ |
|
33289 | 1117 |
requireInitialized(); |
2 | 1118 |
if (writeReplaceMethod != null) { |
1119 |
try { |
|
1120 |
return writeReplaceMethod.invoke(obj, (Object[]) null); |
|
1121 |
} catch (InvocationTargetException ex) { |
|
1122 |
Throwable th = ex.getTargetException(); |
|
1123 |
if (th instanceof ObjectStreamException) { |
|
1124 |
throw (ObjectStreamException) th; |
|
1125 |
} else { |
|
1126 |
throwMiscException(th); |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1127 |
throw new InternalError(th); // never reached |
2 | 1128 |
} |
1129 |
} catch (IllegalAccessException ex) { |
|
1130 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1131 |
throw new InternalError(ex); |
2 | 1132 |
} |
1133 |
} else { |
|
1134 |
throw new UnsupportedOperationException(); |
|
1135 |
} |
|
1136 |
} |
|
1137 |
||
1138 |
/** |
|
1139 |
* Invokes the readResolve method of the represented serializable class and |
|
1140 |
* returns the result. Throws UnsupportedOperationException if this class |
|
1141 |
* descriptor is not associated with a class, or if the class is |
|
1142 |
* non-serializable or does not define readResolve. |
|
1143 |
*/ |
|
1144 |
Object invokeReadResolve(Object obj) |
|
1145 |
throws IOException, UnsupportedOperationException |
|
1146 |
{ |
|
33289 | 1147 |
requireInitialized(); |
2 | 1148 |
if (readResolveMethod != null) { |
1149 |
try { |
|
1150 |
return readResolveMethod.invoke(obj, (Object[]) null); |
|
1151 |
} catch (InvocationTargetException ex) { |
|
1152 |
Throwable th = ex.getTargetException(); |
|
1153 |
if (th instanceof ObjectStreamException) { |
|
1154 |
throw (ObjectStreamException) th; |
|
1155 |
} else { |
|
1156 |
throwMiscException(th); |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1157 |
throw new InternalError(th); // never reached |
2 | 1158 |
} |
1159 |
} catch (IllegalAccessException ex) { |
|
1160 |
// should not occur, as access checks have been suppressed |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1161 |
throw new InternalError(ex); |
2 | 1162 |
} |
1163 |
} else { |
|
1164 |
throw new UnsupportedOperationException(); |
|
1165 |
} |
|
1166 |
} |
|
1167 |
||
1168 |
/** |
|
1169 |
* Class representing the portion of an object's serialized form allotted |
|
1170 |
* to data described by a given class descriptor. If "hasData" is false, |
|
1171 |
* the object's serialized form does not contain data associated with the |
|
1172 |
* class descriptor. |
|
1173 |
*/ |
|
1174 |
static class ClassDataSlot { |
|
1175 |
||
1176 |
/** class descriptor "occupying" this slot */ |
|
1177 |
final ObjectStreamClass desc; |
|
1178 |
/** true if serialized form includes data for this slot's descriptor */ |
|
1179 |
final boolean hasData; |
|
1180 |
||
1181 |
ClassDataSlot(ObjectStreamClass desc, boolean hasData) { |
|
1182 |
this.desc = desc; |
|
1183 |
this.hasData = hasData; |
|
1184 |
} |
|
1185 |
} |
|
1186 |
||
1187 |
/** |
|
1188 |
* Returns array of ClassDataSlot instances representing the data layout |
|
1189 |
* (including superclass data) for serialized objects described by this |
|
1190 |
* class descriptor. ClassDataSlots are ordered by inheritance with those |
|
1191 |
* containing "higher" superclasses appearing first. The final |
|
1192 |
* ClassDataSlot contains a reference to this descriptor. |
|
1193 |
*/ |
|
1194 |
ClassDataSlot[] getClassDataLayout() throws InvalidClassException { |
|
1195 |
// REMIND: synchronize instead of relying on volatile? |
|
1196 |
if (dataLayout == null) { |
|
1197 |
dataLayout = getClassDataLayout0(); |
|
1198 |
} |
|
1199 |
return dataLayout; |
|
1200 |
} |
|
1201 |
||
1202 |
private ClassDataSlot[] getClassDataLayout0() |
|
1203 |
throws InvalidClassException |
|
1204 |
{ |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
1205 |
ArrayList<ClassDataSlot> slots = new ArrayList<>(); |
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1206 |
Class<?> start = cl, end = cl; |
2 | 1207 |
|
1208 |
// locate closest non-serializable superclass |
|
1209 |
while (end != null && Serializable.class.isAssignableFrom(end)) { |
|
1210 |
end = end.getSuperclass(); |
|
1211 |
} |
|
1212 |
||
18186 | 1213 |
HashSet<String> oscNames = new HashSet<>(3); |
1214 |
||
2 | 1215 |
for (ObjectStreamClass d = this; d != null; d = d.superDesc) { |
18186 | 1216 |
if (oscNames.contains(d.name)) { |
1217 |
throw new InvalidClassException("Circular reference."); |
|
1218 |
} else { |
|
1219 |
oscNames.add(d.name); |
|
1220 |
} |
|
2 | 1221 |
|
1222 |
// search up inheritance hierarchy for class with matching name |
|
1223 |
String searchName = (d.cl != null) ? d.cl.getName() : d.name; |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1224 |
Class<?> match = null; |
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1225 |
for (Class<?> c = start; c != end; c = c.getSuperclass()) { |
2 | 1226 |
if (searchName.equals(c.getName())) { |
1227 |
match = c; |
|
1228 |
break; |
|
1229 |
} |
|
1230 |
} |
|
1231 |
||
1232 |
// add "no data" slot for each unmatched class below match |
|
1233 |
if (match != null) { |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1234 |
for (Class<?> c = start; c != match; c = c.getSuperclass()) { |
2 | 1235 |
slots.add(new ClassDataSlot( |
1236 |
ObjectStreamClass.lookup(c, true), false)); |
|
1237 |
} |
|
1238 |
start = match.getSuperclass(); |
|
1239 |
} |
|
1240 |
||
1241 |
// record descriptor/class pairing |
|
1242 |
slots.add(new ClassDataSlot(d.getVariantFor(match), true)); |
|
1243 |
} |
|
1244 |
||
1245 |
// add "no data" slot for any leftover unmatched classes |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1246 |
for (Class<?> c = start; c != end; c = c.getSuperclass()) { |
2 | 1247 |
slots.add(new ClassDataSlot( |
1248 |
ObjectStreamClass.lookup(c, true), false)); |
|
1249 |
} |
|
1250 |
||
1251 |
// order slots from superclass -> subclass |
|
1252 |
Collections.reverse(slots); |
|
51 | 1253 |
return slots.toArray(new ClassDataSlot[slots.size()]); |
2 | 1254 |
} |
1255 |
||
1256 |
/** |
|
1257 |
* Returns aggregate size (in bytes) of marshalled primitive field values |
|
1258 |
* for represented class. |
|
1259 |
*/ |
|
1260 |
int getPrimDataSize() { |
|
1261 |
return primDataSize; |
|
1262 |
} |
|
1263 |
||
1264 |
/** |
|
1265 |
* Returns number of non-primitive serializable fields of represented |
|
1266 |
* class. |
|
1267 |
*/ |
|
1268 |
int getNumObjFields() { |
|
1269 |
return numObjFields; |
|
1270 |
} |
|
1271 |
||
1272 |
/** |
|
1273 |
* Fetches the serializable primitive field values of object obj and |
|
1274 |
* marshals them into byte array buf starting at offset 0. It is the |
|
1275 |
* responsibility of the caller to ensure that obj is of the proper type if |
|
1276 |
* non-null. |
|
1277 |
*/ |
|
1278 |
void getPrimFieldValues(Object obj, byte[] buf) { |
|
1279 |
fieldRefl.getPrimFieldValues(obj, buf); |
|
1280 |
} |
|
1281 |
||
1282 |
/** |
|
1283 |
* Sets the serializable primitive fields of object obj using values |
|
1284 |
* unmarshalled from byte array buf starting at offset 0. It is the |
|
1285 |
* responsibility of the caller to ensure that obj is of the proper type if |
|
1286 |
* non-null. |
|
1287 |
*/ |
|
1288 |
void setPrimFieldValues(Object obj, byte[] buf) { |
|
1289 |
fieldRefl.setPrimFieldValues(obj, buf); |
|
1290 |
} |
|
1291 |
||
1292 |
/** |
|
1293 |
* Fetches the serializable object field values of object obj and stores |
|
1294 |
* them in array vals starting at offset 0. It is the responsibility of |
|
1295 |
* the caller to ensure that obj is of the proper type if non-null. |
|
1296 |
*/ |
|
1297 |
void getObjFieldValues(Object obj, Object[] vals) { |
|
1298 |
fieldRefl.getObjFieldValues(obj, vals); |
|
1299 |
} |
|
1300 |
||
1301 |
/** |
|
30911
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1302 |
* Checks that the given values, from array vals starting at offset 0, |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1303 |
* are assignable to the given serializable object fields. |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1304 |
* @throws ClassCastException if any value is not assignable |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1305 |
*/ |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1306 |
void checkObjFieldValueTypes(Object obj, Object[] vals) { |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1307 |
fieldRefl.checkObjectFieldValueTypes(obj, vals); |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1308 |
} |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1309 |
|
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
1310 |
/** |
2 | 1311 |
* Sets the serializable object fields of object obj using values from |
1312 |
* array vals starting at offset 0. It is the responsibility of the caller |
|
1313 |
* to ensure that obj is of the proper type if non-null. |
|
1314 |
*/ |
|
1315 |
void setObjFieldValues(Object obj, Object[] vals) { |
|
1316 |
fieldRefl.setObjFieldValues(obj, vals); |
|
1317 |
} |
|
1318 |
||
1319 |
/** |
|
1320 |
* Calculates and sets serializable field offsets, as well as primitive |
|
1321 |
* data size and object field count totals. Throws InvalidClassException |
|
1322 |
* if fields are illegally ordered. |
|
1323 |
*/ |
|
1324 |
private void computeFieldOffsets() throws InvalidClassException { |
|
1325 |
primDataSize = 0; |
|
1326 |
numObjFields = 0; |
|
1327 |
int firstObjIndex = -1; |
|
1328 |
||
1329 |
for (int i = 0; i < fields.length; i++) { |
|
1330 |
ObjectStreamField f = fields[i]; |
|
1331 |
switch (f.getTypeCode()) { |
|
1332 |
case 'Z': |
|
1333 |
case 'B': |
|
1334 |
f.setOffset(primDataSize++); |
|
1335 |
break; |
|
1336 |
||
1337 |
case 'C': |
|
1338 |
case 'S': |
|
1339 |
f.setOffset(primDataSize); |
|
1340 |
primDataSize += 2; |
|
1341 |
break; |
|
1342 |
||
1343 |
case 'I': |
|
1344 |
case 'F': |
|
1345 |
f.setOffset(primDataSize); |
|
1346 |
primDataSize += 4; |
|
1347 |
break; |
|
1348 |
||
1349 |
case 'J': |
|
1350 |
case 'D': |
|
1351 |
f.setOffset(primDataSize); |
|
1352 |
primDataSize += 8; |
|
1353 |
break; |
|
1354 |
||
1355 |
case '[': |
|
1356 |
case 'L': |
|
1357 |
f.setOffset(numObjFields++); |
|
1358 |
if (firstObjIndex == -1) { |
|
1359 |
firstObjIndex = i; |
|
1360 |
} |
|
1361 |
break; |
|
1362 |
||
1363 |
default: |
|
1364 |
throw new InternalError(); |
|
1365 |
} |
|
1366 |
} |
|
1367 |
if (firstObjIndex != -1 && |
|
1368 |
firstObjIndex + numObjFields != fields.length) |
|
1369 |
{ |
|
1370 |
throw new InvalidClassException(name, "illegal field order"); |
|
1371 |
} |
|
1372 |
} |
|
1373 |
||
1374 |
/** |
|
1375 |
* If given class is the same as the class associated with this class |
|
1376 |
* descriptor, returns reference to this class descriptor. Otherwise, |
|
1377 |
* returns variant of this class descriptor bound to given class. |
|
1378 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1379 |
private ObjectStreamClass getVariantFor(Class<?> cl) |
2 | 1380 |
throws InvalidClassException |
1381 |
{ |
|
1382 |
if (this.cl == cl) { |
|
1383 |
return this; |
|
1384 |
} |
|
1385 |
ObjectStreamClass desc = new ObjectStreamClass(); |
|
1386 |
if (isProxy) { |
|
1387 |
desc.initProxy(cl, null, superDesc); |
|
1388 |
} else { |
|
1389 |
desc.initNonProxy(this, cl, null, superDesc); |
|
1390 |
} |
|
1391 |
return desc; |
|
1392 |
} |
|
1393 |
||
1394 |
/** |
|
1395 |
* Returns public no-arg constructor of given class, or null if none found. |
|
1396 |
* Access checks are disabled on the returned constructor (if any), since |
|
1397 |
* the defining class may still be non-public. |
|
1398 |
*/ |
|
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
1399 |
private static Constructor<?> getExternalizableConstructor(Class<?> cl) { |
2 | 1400 |
try { |
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
1401 |
Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null); |
2 | 1402 |
cons.setAccessible(true); |
1403 |
return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? |
|
1404 |
cons : null; |
|
1405 |
} catch (NoSuchMethodException ex) { |
|
1406 |
return null; |
|
1407 |
} |
|
1408 |
} |
|
1409 |
||
1410 |
/** |
|
1411 |
* Returns subclass-accessible no-arg constructor of first non-serializable |
|
1412 |
* superclass, or null if none found. Access checks are disabled on the |
|
1413 |
* returned constructor (if any). |
|
1414 |
*/ |
|
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
1415 |
private static Constructor<?> getSerializableConstructor(Class<?> cl) { |
51 | 1416 |
Class<?> initCl = cl; |
2 | 1417 |
while (Serializable.class.isAssignableFrom(initCl)) { |
1418 |
if ((initCl = initCl.getSuperclass()) == null) { |
|
1419 |
return null; |
|
1420 |
} |
|
1421 |
} |
|
1422 |
try { |
|
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
1423 |
Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null); |
2 | 1424 |
int mods = cons.getModifiers(); |
1425 |
if ((mods & Modifier.PRIVATE) != 0 || |
|
1426 |
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 && |
|
1427 |
!packageEquals(cl, initCl))) |
|
1428 |
{ |
|
1429 |
return null; |
|
1430 |
} |
|
1431 |
cons = reflFactory.newConstructorForSerialization(cl, cons); |
|
1432 |
cons.setAccessible(true); |
|
1433 |
return cons; |
|
1434 |
} catch (NoSuchMethodException ex) { |
|
1435 |
return null; |
|
1436 |
} |
|
1437 |
} |
|
1438 |
||
1439 |
/** |
|
1440 |
* Returns non-static, non-abstract method with given signature provided it |
|
1441 |
* is defined by or accessible (via inheritance) by the given class, or |
|
1442 |
* null if no match found. Access checks are disabled on the returned |
|
1443 |
* method (if any). |
|
1444 |
*/ |
|
51 | 1445 |
private static Method getInheritableMethod(Class<?> cl, String name, |
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1446 |
Class<?>[] argTypes, |
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1447 |
Class<?> returnType) |
2 | 1448 |
{ |
1449 |
Method meth = null; |
|
51 | 1450 |
Class<?> defCl = cl; |
2 | 1451 |
while (defCl != null) { |
1452 |
try { |
|
1453 |
meth = defCl.getDeclaredMethod(name, argTypes); |
|
1454 |
break; |
|
1455 |
} catch (NoSuchMethodException ex) { |
|
1456 |
defCl = defCl.getSuperclass(); |
|
1457 |
} |
|
1458 |
} |
|
1459 |
||
1460 |
if ((meth == null) || (meth.getReturnType() != returnType)) { |
|
1461 |
return null; |
|
1462 |
} |
|
1463 |
meth.setAccessible(true); |
|
1464 |
int mods = meth.getModifiers(); |
|
1465 |
if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { |
|
1466 |
return null; |
|
1467 |
} else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { |
|
1468 |
return meth; |
|
1469 |
} else if ((mods & Modifier.PRIVATE) != 0) { |
|
1470 |
return (cl == defCl) ? meth : null; |
|
1471 |
} else { |
|
1472 |
return packageEquals(cl, defCl) ? meth : null; |
|
1473 |
} |
|
1474 |
} |
|
1475 |
||
1476 |
/** |
|
1477 |
* Returns non-static private method with given signature defined by given |
|
1478 |
* class, or null if none found. Access checks are disabled on the |
|
1479 |
* returned method (if any). |
|
1480 |
*/ |
|
51 | 1481 |
private static Method getPrivateMethod(Class<?> cl, String name, |
1482 |
Class<?>[] argTypes, |
|
1483 |
Class<?> returnType) |
|
2 | 1484 |
{ |
1485 |
try { |
|
1486 |
Method meth = cl.getDeclaredMethod(name, argTypes); |
|
1487 |
meth.setAccessible(true); |
|
1488 |
int mods = meth.getModifiers(); |
|
1489 |
return ((meth.getReturnType() == returnType) && |
|
1490 |
((mods & Modifier.STATIC) == 0) && |
|
1491 |
((mods & Modifier.PRIVATE) != 0)) ? meth : null; |
|
1492 |
} catch (NoSuchMethodException ex) { |
|
1493 |
return null; |
|
1494 |
} |
|
1495 |
} |
|
1496 |
||
1497 |
/** |
|
1498 |
* Returns true if classes are defined in the same runtime package, false |
|
1499 |
* otherwise. |
|
1500 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1501 |
private static boolean packageEquals(Class<?> cl1, Class<?> cl2) { |
2 | 1502 |
return (cl1.getClassLoader() == cl2.getClassLoader() && |
1503 |
getPackageName(cl1).equals(getPackageName(cl2))); |
|
1504 |
} |
|
1505 |
||
1506 |
/** |
|
1507 |
* Returns package name of given class. |
|
1508 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1509 |
private static String getPackageName(Class<?> cl) { |
2 | 1510 |
String s = cl.getName(); |
1511 |
int i = s.lastIndexOf('['); |
|
1512 |
if (i >= 0) { |
|
1513 |
s = s.substring(i + 2); |
|
1514 |
} |
|
1515 |
i = s.lastIndexOf('.'); |
|
1516 |
return (i >= 0) ? s.substring(0, i) : ""; |
|
1517 |
} |
|
1518 |
||
1519 |
/** |
|
1520 |
* Compares class names for equality, ignoring package names. Returns true |
|
1521 |
* if class names equal, false otherwise. |
|
1522 |
*/ |
|
1523 |
private static boolean classNamesEqual(String name1, String name2) { |
|
34357
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1524 |
int idx1 = name1.lastIndexOf('.') + 1; |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1525 |
int idx2 = name2.lastIndexOf('.') + 1; |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1526 |
int len1 = name1.length() - idx1; |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1527 |
int len2 = name2.length() - idx2; |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1528 |
return len1 == len2 && |
231fdaed751a
8143926: ObjectStreamField constructor eagerly load ObjectStreamClass
redestad
parents:
33674
diff
changeset
|
1529 |
name1.regionMatches(idx1, name2, idx2, len1); |
2 | 1530 |
} |
1531 |
||
1532 |
/** |
|
1533 |
* Returns JVM type signature for given list of parameters and return type. |
|
1534 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1535 |
private static String getMethodSignature(Class<?>[] paramTypes, |
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1536 |
Class<?> retType) |
2 | 1537 |
{ |
1538 |
StringBuilder sbuf = new StringBuilder(); |
|
1539 |
sbuf.append('('); |
|
1540 |
for (int i = 0; i < paramTypes.length; i++) { |
|
22936 | 1541 |
appendClassSignature(sbuf, paramTypes[i]); |
2 | 1542 |
} |
1543 |
sbuf.append(')'); |
|
22936 | 1544 |
appendClassSignature(sbuf, retType); |
2 | 1545 |
return sbuf.toString(); |
1546 |
} |
|
1547 |
||
1548 |
/** |
|
1549 |
* Convenience method for throwing an exception that is either a |
|
1550 |
* RuntimeException, Error, or of some unexpected type (in which case it is |
|
1551 |
* wrapped inside an IOException). |
|
1552 |
*/ |
|
1553 |
private static void throwMiscException(Throwable th) throws IOException { |
|
1554 |
if (th instanceof RuntimeException) { |
|
1555 |
throw (RuntimeException) th; |
|
1556 |
} else if (th instanceof Error) { |
|
1557 |
throw (Error) th; |
|
1558 |
} else { |
|
1559 |
IOException ex = new IOException("unexpected exception type"); |
|
1560 |
ex.initCause(th); |
|
1561 |
throw ex; |
|
1562 |
} |
|
1563 |
} |
|
1564 |
||
1565 |
/** |
|
1566 |
* Returns ObjectStreamField array describing the serializable fields of |
|
1567 |
* the given class. Serializable fields backed by an actual field of the |
|
1568 |
* class are represented by ObjectStreamFields with corresponding non-null |
|
1569 |
* Field objects. Throws InvalidClassException if the (explicitly |
|
1570 |
* declared) serializable fields are invalid. |
|
1571 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1572 |
private static ObjectStreamField[] getSerialFields(Class<?> cl) |
2 | 1573 |
throws InvalidClassException |
1574 |
{ |
|
1575 |
ObjectStreamField[] fields; |
|
1576 |
if (Serializable.class.isAssignableFrom(cl) && |
|
1577 |
!Externalizable.class.isAssignableFrom(cl) && |
|
1578 |
!Proxy.isProxyClass(cl) && |
|
1579 |
!cl.isInterface()) |
|
1580 |
{ |
|
1581 |
if ((fields = getDeclaredSerialFields(cl)) == null) { |
|
1582 |
fields = getDefaultSerialFields(cl); |
|
1583 |
} |
|
1584 |
Arrays.sort(fields); |
|
1585 |
} else { |
|
1586 |
fields = NO_FIELDS; |
|
1587 |
} |
|
1588 |
return fields; |
|
1589 |
} |
|
1590 |
||
1591 |
/** |
|
1592 |
* Returns serializable fields of given class as defined explicitly by a |
|
1593 |
* "serialPersistentFields" field, or null if no appropriate |
|
1594 |
* "serialPersistentFields" field is defined. Serializable fields backed |
|
1595 |
* by an actual field of the class are represented by ObjectStreamFields |
|
1596 |
* with corresponding non-null Field objects. For compatibility with past |
|
1597 |
* releases, a "serialPersistentFields" field with a null value is |
|
1598 |
* considered equivalent to not declaring "serialPersistentFields". Throws |
|
1599 |
* InvalidClassException if the declared serializable fields are |
|
1600 |
* invalid--e.g., if multiple fields share the same name. |
|
1601 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1602 |
private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl) |
2 | 1603 |
throws InvalidClassException |
1604 |
{ |
|
1605 |
ObjectStreamField[] serialPersistentFields = null; |
|
1606 |
try { |
|
1607 |
Field f = cl.getDeclaredField("serialPersistentFields"); |
|
1608 |
int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; |
|
1609 |
if ((f.getModifiers() & mask) == mask) { |
|
1610 |
f.setAccessible(true); |
|
1611 |
serialPersistentFields = (ObjectStreamField[]) f.get(null); |
|
1612 |
} |
|
1613 |
} catch (Exception ex) { |
|
1614 |
} |
|
1615 |
if (serialPersistentFields == null) { |
|
1616 |
return null; |
|
1617 |
} else if (serialPersistentFields.length == 0) { |
|
1618 |
return NO_FIELDS; |
|
1619 |
} |
|
1620 |
||
1621 |
ObjectStreamField[] boundFields = |
|
1622 |
new ObjectStreamField[serialPersistentFields.length]; |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
1623 |
Set<String> fieldNames = new HashSet<>(serialPersistentFields.length); |
2 | 1624 |
|
1625 |
for (int i = 0; i < serialPersistentFields.length; i++) { |
|
1626 |
ObjectStreamField spf = serialPersistentFields[i]; |
|
1627 |
||
1628 |
String fname = spf.getName(); |
|
1629 |
if (fieldNames.contains(fname)) { |
|
1630 |
throw new InvalidClassException( |
|
1631 |
"multiple serializable fields named " + fname); |
|
1632 |
} |
|
1633 |
fieldNames.add(fname); |
|
1634 |
||
1635 |
try { |
|
1636 |
Field f = cl.getDeclaredField(fname); |
|
1637 |
if ((f.getType() == spf.getType()) && |
|
1638 |
((f.getModifiers() & Modifier.STATIC) == 0)) |
|
1639 |
{ |
|
1640 |
boundFields[i] = |
|
1641 |
new ObjectStreamField(f, spf.isUnshared(), true); |
|
1642 |
} |
|
1643 |
} catch (NoSuchFieldException ex) { |
|
1644 |
} |
|
1645 |
if (boundFields[i] == null) { |
|
1646 |
boundFields[i] = new ObjectStreamField( |
|
1647 |
fname, spf.getType(), spf.isUnshared()); |
|
1648 |
} |
|
1649 |
} |
|
1650 |
return boundFields; |
|
1651 |
} |
|
1652 |
||
1653 |
/** |
|
1654 |
* Returns array of ObjectStreamFields corresponding to all non-static |
|
1655 |
* non-transient fields declared by given class. Each ObjectStreamField |
|
1656 |
* contains a Field object for the field it represents. If no default |
|
1657 |
* serializable fields exist, NO_FIELDS is returned. |
|
1658 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1659 |
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) { |
2 | 1660 |
Field[] clFields = cl.getDeclaredFields(); |
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
1661 |
ArrayList<ObjectStreamField> list = new ArrayList<>(); |
2 | 1662 |
int mask = Modifier.STATIC | Modifier.TRANSIENT; |
1663 |
||
1664 |
for (int i = 0; i < clFields.length; i++) { |
|
1665 |
if ((clFields[i].getModifiers() & mask) == 0) { |
|
1666 |
list.add(new ObjectStreamField(clFields[i], false, true)); |
|
1667 |
} |
|
1668 |
} |
|
1669 |
int size = list.size(); |
|
1670 |
return (size == 0) ? NO_FIELDS : |
|
51 | 1671 |
list.toArray(new ObjectStreamField[size]); |
2 | 1672 |
} |
1673 |
||
1674 |
/** |
|
1675 |
* Returns explicit serial version UID value declared by given class, or |
|
1676 |
* null if none. |
|
1677 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1678 |
private static Long getDeclaredSUID(Class<?> cl) { |
2 | 1679 |
try { |
1680 |
Field f = cl.getDeclaredField("serialVersionUID"); |
|
1681 |
int mask = Modifier.STATIC | Modifier.FINAL; |
|
1682 |
if ((f.getModifiers() & mask) == mask) { |
|
1683 |
f.setAccessible(true); |
|
1684 |
return Long.valueOf(f.getLong(null)); |
|
1685 |
} |
|
1686 |
} catch (Exception ex) { |
|
1687 |
} |
|
1688 |
return null; |
|
1689 |
} |
|
1690 |
||
1691 |
/** |
|
1692 |
* Computes the default serial version UID value for the given class. |
|
1693 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1694 |
private static long computeDefaultSUID(Class<?> cl) { |
2 | 1695 |
if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) |
1696 |
{ |
|
1697 |
return 0L; |
|
1698 |
} |
|
1699 |
||
1700 |
try { |
|
1701 |
ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
|
1702 |
DataOutputStream dout = new DataOutputStream(bout); |
|
1703 |
||
1704 |
dout.writeUTF(cl.getName()); |
|
1705 |
||
1706 |
int classMods = cl.getModifiers() & |
|
1707 |
(Modifier.PUBLIC | Modifier.FINAL | |
|
1708 |
Modifier.INTERFACE | Modifier.ABSTRACT); |
|
1709 |
||
1710 |
/* |
|
1711 |
* compensate for javac bug in which ABSTRACT bit was set for an |
|
1712 |
* interface only if the interface declared methods |
|
1713 |
*/ |
|
1714 |
Method[] methods = cl.getDeclaredMethods(); |
|
1715 |
if ((classMods & Modifier.INTERFACE) != 0) { |
|
1716 |
classMods = (methods.length > 0) ? |
|
1717 |
(classMods | Modifier.ABSTRACT) : |
|
1718 |
(classMods & ~Modifier.ABSTRACT); |
|
1719 |
} |
|
1720 |
dout.writeInt(classMods); |
|
1721 |
||
1722 |
if (!cl.isArray()) { |
|
1723 |
/* |
|
1724 |
* compensate for change in 1.2FCS in which |
|
1725 |
* Class.getInterfaces() was modified to return Cloneable and |
|
1726 |
* Serializable for array classes. |
|
1727 |
*/ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1728 |
Class<?>[] interfaces = cl.getInterfaces(); |
2 | 1729 |
String[] ifaceNames = new String[interfaces.length]; |
1730 |
for (int i = 0; i < interfaces.length; i++) { |
|
1731 |
ifaceNames[i] = interfaces[i].getName(); |
|
1732 |
} |
|
1733 |
Arrays.sort(ifaceNames); |
|
1734 |
for (int i = 0; i < ifaceNames.length; i++) { |
|
1735 |
dout.writeUTF(ifaceNames[i]); |
|
1736 |
} |
|
1737 |
} |
|
1738 |
||
1739 |
Field[] fields = cl.getDeclaredFields(); |
|
1740 |
MemberSignature[] fieldSigs = new MemberSignature[fields.length]; |
|
1741 |
for (int i = 0; i < fields.length; i++) { |
|
1742 |
fieldSigs[i] = new MemberSignature(fields[i]); |
|
1743 |
} |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
1744 |
Arrays.sort(fieldSigs, new Comparator<>() { |
51 | 1745 |
public int compare(MemberSignature ms1, MemberSignature ms2) { |
1746 |
return ms1.name.compareTo(ms2.name); |
|
2 | 1747 |
} |
1748 |
}); |
|
1749 |
for (int i = 0; i < fieldSigs.length; i++) { |
|
1750 |
MemberSignature sig = fieldSigs[i]; |
|
1751 |
int mods = sig.member.getModifiers() & |
|
1752 |
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | |
|
1753 |
Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | |
|
1754 |
Modifier.TRANSIENT); |
|
1755 |
if (((mods & Modifier.PRIVATE) == 0) || |
|
1756 |
((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) |
|
1757 |
{ |
|
1758 |
dout.writeUTF(sig.name); |
|
1759 |
dout.writeInt(mods); |
|
1760 |
dout.writeUTF(sig.signature); |
|
1761 |
} |
|
1762 |
} |
|
1763 |
||
1764 |
if (hasStaticInitializer(cl)) { |
|
1765 |
dout.writeUTF("<clinit>"); |
|
1766 |
dout.writeInt(Modifier.STATIC); |
|
1767 |
dout.writeUTF("()V"); |
|
1768 |
} |
|
1769 |
||
21655
55f32ae4f920
8028229: Fix more raw types lint warning in core libraries
darcy
parents:
18260
diff
changeset
|
1770 |
Constructor<?>[] cons = cl.getDeclaredConstructors(); |
2 | 1771 |
MemberSignature[] consSigs = new MemberSignature[cons.length]; |
1772 |
for (int i = 0; i < cons.length; i++) { |
|
1773 |
consSigs[i] = new MemberSignature(cons[i]); |
|
1774 |
} |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
1775 |
Arrays.sort(consSigs, new Comparator<>() { |
51 | 1776 |
public int compare(MemberSignature ms1, MemberSignature ms2) { |
1777 |
return ms1.signature.compareTo(ms2.signature); |
|
2 | 1778 |
} |
1779 |
}); |
|
1780 |
for (int i = 0; i < consSigs.length; i++) { |
|
1781 |
MemberSignature sig = consSigs[i]; |
|
1782 |
int mods = sig.member.getModifiers() & |
|
1783 |
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | |
|
1784 |
Modifier.STATIC | Modifier.FINAL | |
|
1785 |
Modifier.SYNCHRONIZED | Modifier.NATIVE | |
|
1786 |
Modifier.ABSTRACT | Modifier.STRICT); |
|
1787 |
if ((mods & Modifier.PRIVATE) == 0) { |
|
1788 |
dout.writeUTF("<init>"); |
|
1789 |
dout.writeInt(mods); |
|
1790 |
dout.writeUTF(sig.signature.replace('/', '.')); |
|
1791 |
} |
|
1792 |
} |
|
1793 |
||
1794 |
MemberSignature[] methSigs = new MemberSignature[methods.length]; |
|
1795 |
for (int i = 0; i < methods.length; i++) { |
|
1796 |
methSigs[i] = new MemberSignature(methods[i]); |
|
1797 |
} |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
1798 |
Arrays.sort(methSigs, new Comparator<>() { |
51 | 1799 |
public int compare(MemberSignature ms1, MemberSignature ms2) { |
2 | 1800 |
int comp = ms1.name.compareTo(ms2.name); |
1801 |
if (comp == 0) { |
|
1802 |
comp = ms1.signature.compareTo(ms2.signature); |
|
1803 |
} |
|
1804 |
return comp; |
|
1805 |
} |
|
1806 |
}); |
|
1807 |
for (int i = 0; i < methSigs.length; i++) { |
|
1808 |
MemberSignature sig = methSigs[i]; |
|
1809 |
int mods = sig.member.getModifiers() & |
|
1810 |
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | |
|
1811 |
Modifier.STATIC | Modifier.FINAL | |
|
1812 |
Modifier.SYNCHRONIZED | Modifier.NATIVE | |
|
1813 |
Modifier.ABSTRACT | Modifier.STRICT); |
|
1814 |
if ((mods & Modifier.PRIVATE) == 0) { |
|
1815 |
dout.writeUTF(sig.name); |
|
1816 |
dout.writeInt(mods); |
|
1817 |
dout.writeUTF(sig.signature.replace('/', '.')); |
|
1818 |
} |
|
1819 |
} |
|
1820 |
||
1821 |
dout.flush(); |
|
1822 |
||
1823 |
MessageDigest md = MessageDigest.getInstance("SHA"); |
|
1824 |
byte[] hashBytes = md.digest(bout.toByteArray()); |
|
1825 |
long hash = 0; |
|
1826 |
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { |
|
1827 |
hash = (hash << 8) | (hashBytes[i] & 0xFF); |
|
1828 |
} |
|
1829 |
return hash; |
|
1830 |
} catch (IOException ex) { |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
9035
diff
changeset
|
1831 |
throw new InternalError(ex); |
2 | 1832 |
} catch (NoSuchAlgorithmException ex) { |
1833 |
throw new SecurityException(ex.getMessage()); |
|
1834 |
} |
|
1835 |
} |
|
1836 |
||
1837 |
/** |
|
1838 |
* Returns true if the given class defines a static initializer method, |
|
1839 |
* false otherwise. |
|
1840 |
*/ |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
30911
diff
changeset
|
1841 |
private static native boolean hasStaticInitializer(Class<?> cl); |
2 | 1842 |
|
1843 |
/** |
|
1844 |
* Class for computing and caching field/constructor/method signatures |
|
1845 |
* during serialVersionUID calculation. |
|
1846 |
*/ |
|
1847 |
private static class MemberSignature { |
|
1848 |
||
1849 |
public final Member member; |
|
1850 |
public final String name; |
|
1851 |
public final String signature; |
|
1852 |
||
1853 |
public MemberSignature(Field field) { |
|
1854 |
member = field; |
|
1855 |
name = field.getName(); |
|
1856 |
signature = getClassSignature(field.getType()); |
|
1857 |
} |
|
1858 |
||
11117
b6e68b1344d4
7116404: Miscellaneous warnings (java.rmi.**, serialization, some core classes)
alanb
parents:
10419
diff
changeset
|
1859 |
public MemberSignature(Constructor<?> cons) { |
2 | 1860 |
member = cons; |
1861 |
name = cons.getName(); |
|
1862 |
signature = getMethodSignature( |
|
1863 |
cons.getParameterTypes(), Void.TYPE); |
|
1864 |
} |
|
1865 |
||
1866 |
public MemberSignature(Method meth) { |
|
1867 |
member = meth; |
|
1868 |
name = meth.getName(); |
|
1869 |
signature = getMethodSignature( |
|
1870 |
meth.getParameterTypes(), meth.getReturnType()); |
|
1871 |
} |
|
1872 |
} |
|
1873 |
||
1874 |
/** |
|
1875 |
* Class for setting and retrieving serializable field values in batch. |
|
1876 |
*/ |
|
1877 |
// REMIND: dynamically generate these? |
|
1878 |
private static class FieldReflector { |
|
1879 |
||
1880 |
/** handle for performing unsafe operations */ |
|
1881 |
private static final Unsafe unsafe = Unsafe.getUnsafe(); |
|
1882 |
||
1883 |
/** fields to operate on */ |
|
1884 |
private final ObjectStreamField[] fields; |
|
1885 |
/** number of primitive fields */ |
|
1886 |
private final int numPrimFields; |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1887 |
/** unsafe field keys for reading fields - may contain dupes */ |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1888 |
private final long[] readKeys; |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1889 |
/** unsafe fields keys for writing fields - no dupes */ |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1890 |
private final long[] writeKeys; |
2 | 1891 |
/** field data offsets */ |
1892 |
private final int[] offsets; |
|
1893 |
/** field type codes */ |
|
1894 |
private final char[] typeCodes; |
|
1895 |
/** field types */ |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
1896 |
private final Class<?>[] types; |
2 | 1897 |
|
1898 |
/** |
|
1899 |
* Constructs FieldReflector capable of setting/getting values from the |
|
1900 |
* subset of fields whose ObjectStreamFields contain non-null |
|
1901 |
* reflective Field objects. ObjectStreamFields with null Fields are |
|
1902 |
* treated as filler, for which get operations return default values |
|
1903 |
* and set operations discard given values. |
|
1904 |
*/ |
|
1905 |
FieldReflector(ObjectStreamField[] fields) { |
|
1906 |
this.fields = fields; |
|
1907 |
int nfields = fields.length; |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1908 |
readKeys = new long[nfields]; |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1909 |
writeKeys = new long[nfields]; |
2 | 1910 |
offsets = new int[nfields]; |
1911 |
typeCodes = new char[nfields]; |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
1912 |
ArrayList<Class<?>> typeList = new ArrayList<>(); |
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
1913 |
Set<Long> usedKeys = new HashSet<>(); |
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1914 |
|
2 | 1915 |
|
1916 |
for (int i = 0; i < nfields; i++) { |
|
1917 |
ObjectStreamField f = fields[i]; |
|
1918 |
Field rf = f.getField(); |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1919 |
long key = (rf != null) ? |
2 | 1920 |
unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET; |
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1921 |
readKeys[i] = key; |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1922 |
writeKeys[i] = usedKeys.add(key) ? |
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1923 |
key : Unsafe.INVALID_FIELD_OFFSET; |
2 | 1924 |
offsets[i] = f.getOffset(); |
1925 |
typeCodes[i] = f.getTypeCode(); |
|
1926 |
if (!f.isPrimitive()) { |
|
1927 |
typeList.add((rf != null) ? rf.getType() : null); |
|
1928 |
} |
|
1929 |
} |
|
1930 |
||
51 | 1931 |
types = typeList.toArray(new Class<?>[typeList.size()]); |
2 | 1932 |
numPrimFields = nfields - types.length; |
1933 |
} |
|
1934 |
||
1935 |
/** |
|
1936 |
* Returns list of ObjectStreamFields representing fields operated on |
|
1937 |
* by this reflector. The shared/unshared values and Field objects |
|
1938 |
* contained by ObjectStreamFields in the list reflect their bindings |
|
1939 |
* to locally defined serializable fields. |
|
1940 |
*/ |
|
1941 |
ObjectStreamField[] getFields() { |
|
1942 |
return fields; |
|
1943 |
} |
|
1944 |
||
1945 |
/** |
|
1946 |
* Fetches the serializable primitive field values of object obj and |
|
1947 |
* marshals them into byte array buf starting at offset 0. The caller |
|
1948 |
* is responsible for ensuring that obj is of the proper type. |
|
1949 |
*/ |
|
1950 |
void getPrimFieldValues(Object obj, byte[] buf) { |
|
1951 |
if (obj == null) { |
|
1952 |
throw new NullPointerException(); |
|
1953 |
} |
|
1954 |
/* assuming checkDefaultSerialize() has been called on the class |
|
1955 |
* descriptor this FieldReflector was obtained from, no field keys |
|
1956 |
* in array should be equal to Unsafe.INVALID_FIELD_OFFSET. |
|
1957 |
*/ |
|
1958 |
for (int i = 0; i < numPrimFields; i++) { |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
1959 |
long key = readKeys[i]; |
2 | 1960 |
int off = offsets[i]; |
1961 |
switch (typeCodes[i]) { |
|
1962 |
case 'Z': |
|
1963 |
Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key)); |
|
1964 |
break; |
|
1965 |
||
1966 |
case 'B': |
|
1967 |
buf[off] = unsafe.getByte(obj, key); |
|
1968 |
break; |
|
1969 |
||
1970 |
case 'C': |
|
1971 |
Bits.putChar(buf, off, unsafe.getChar(obj, key)); |
|
1972 |
break; |
|
1973 |
||
1974 |
case 'S': |
|
1975 |
Bits.putShort(buf, off, unsafe.getShort(obj, key)); |
|
1976 |
break; |
|
1977 |
||
1978 |
case 'I': |
|
1979 |
Bits.putInt(buf, off, unsafe.getInt(obj, key)); |
|
1980 |
break; |
|
1981 |
||
1982 |
case 'F': |
|
1983 |
Bits.putFloat(buf, off, unsafe.getFloat(obj, key)); |
|
1984 |
break; |
|
1985 |
||
1986 |
case 'J': |
|
1987 |
Bits.putLong(buf, off, unsafe.getLong(obj, key)); |
|
1988 |
break; |
|
1989 |
||
1990 |
case 'D': |
|
1991 |
Bits.putDouble(buf, off, unsafe.getDouble(obj, key)); |
|
1992 |
break; |
|
1993 |
||
1994 |
default: |
|
1995 |
throw new InternalError(); |
|
1996 |
} |
|
1997 |
} |
|
1998 |
} |
|
1999 |
||
2000 |
/** |
|
2001 |
* Sets the serializable primitive fields of object obj using values |
|
2002 |
* unmarshalled from byte array buf starting at offset 0. The caller |
|
2003 |
* is responsible for ensuring that obj is of the proper type. |
|
2004 |
*/ |
|
2005 |
void setPrimFieldValues(Object obj, byte[] buf) { |
|
2006 |
if (obj == null) { |
|
2007 |
throw new NullPointerException(); |
|
2008 |
} |
|
2009 |
for (int i = 0; i < numPrimFields; i++) { |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
2010 |
long key = writeKeys[i]; |
2 | 2011 |
if (key == Unsafe.INVALID_FIELD_OFFSET) { |
2012 |
continue; // discard value |
|
2013 |
} |
|
2014 |
int off = offsets[i]; |
|
2015 |
switch (typeCodes[i]) { |
|
2016 |
case 'Z': |
|
2017 |
unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off)); |
|
2018 |
break; |
|
2019 |
||
2020 |
case 'B': |
|
2021 |
unsafe.putByte(obj, key, buf[off]); |
|
2022 |
break; |
|
2023 |
||
2024 |
case 'C': |
|
2025 |
unsafe.putChar(obj, key, Bits.getChar(buf, off)); |
|
2026 |
break; |
|
2027 |
||
2028 |
case 'S': |
|
2029 |
unsafe.putShort(obj, key, Bits.getShort(buf, off)); |
|
2030 |
break; |
|
2031 |
||
2032 |
case 'I': |
|
2033 |
unsafe.putInt(obj, key, Bits.getInt(buf, off)); |
|
2034 |
break; |
|
2035 |
||
2036 |
case 'F': |
|
2037 |
unsafe.putFloat(obj, key, Bits.getFloat(buf, off)); |
|
2038 |
break; |
|
2039 |
||
2040 |
case 'J': |
|
2041 |
unsafe.putLong(obj, key, Bits.getLong(buf, off)); |
|
2042 |
break; |
|
2043 |
||
2044 |
case 'D': |
|
2045 |
unsafe.putDouble(obj, key, Bits.getDouble(buf, off)); |
|
2046 |
break; |
|
2047 |
||
2048 |
default: |
|
2049 |
throw new InternalError(); |
|
2050 |
} |
|
2051 |
} |
|
2052 |
} |
|
2053 |
||
2054 |
/** |
|
2055 |
* Fetches the serializable object field values of object obj and |
|
2056 |
* stores them in array vals starting at offset 0. The caller is |
|
2057 |
* responsible for ensuring that obj is of the proper type. |
|
2058 |
*/ |
|
2059 |
void getObjFieldValues(Object obj, Object[] vals) { |
|
2060 |
if (obj == null) { |
|
2061 |
throw new NullPointerException(); |
|
2062 |
} |
|
2063 |
/* assuming checkDefaultSerialize() has been called on the class |
|
2064 |
* descriptor this FieldReflector was obtained from, no field keys |
|
2065 |
* in array should be equal to Unsafe.INVALID_FIELD_OFFSET. |
|
2066 |
*/ |
|
2067 |
for (int i = numPrimFields; i < fields.length; i++) { |
|
2068 |
switch (typeCodes[i]) { |
|
2069 |
case 'L': |
|
2070 |
case '[': |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
2071 |
vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]); |
2 | 2072 |
break; |
2073 |
||
2074 |
default: |
|
2075 |
throw new InternalError(); |
|
2076 |
} |
|
2077 |
} |
|
2078 |
} |
|
2079 |
||
2080 |
/** |
|
30911
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2081 |
* Checks that the given values, from array vals starting at offset 0, |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2082 |
* are assignable to the given serializable object fields. |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2083 |
* @throws ClassCastException if any value is not assignable |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2084 |
*/ |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2085 |
void checkObjectFieldValueTypes(Object obj, Object[] vals) { |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2086 |
setObjFieldValues(obj, vals, true); |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2087 |
} |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2088 |
|
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2089 |
/** |
2 | 2090 |
* Sets the serializable object fields of object obj using values from |
2091 |
* array vals starting at offset 0. The caller is responsible for |
|
2092 |
* ensuring that obj is of the proper type; however, attempts to set a |
|
2093 |
* field with a value of the wrong type will trigger an appropriate |
|
2094 |
* ClassCastException. |
|
2095 |
*/ |
|
2096 |
void setObjFieldValues(Object obj, Object[] vals) { |
|
30911
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2097 |
setObjFieldValues(obj, vals, false); |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2098 |
} |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2099 |
|
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2100 |
private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) { |
2 | 2101 |
if (obj == null) { |
2102 |
throw new NullPointerException(); |
|
2103 |
} |
|
2104 |
for (int i = numPrimFields; i < fields.length; i++) { |
|
7031
d77ff2048ad5
6966692: defaultReadObject can set a field multiple times
skoppar
parents:
5506
diff
changeset
|
2105 |
long key = writeKeys[i]; |
2 | 2106 |
if (key == Unsafe.INVALID_FIELD_OFFSET) { |
2107 |
continue; // discard value |
|
2108 |
} |
|
2109 |
switch (typeCodes[i]) { |
|
2110 |
case 'L': |
|
2111 |
case '[': |
|
2112 |
Object val = vals[offsets[i]]; |
|
2113 |
if (val != null && |
|
2114 |
!types[i - numPrimFields].isInstance(val)) |
|
2115 |
{ |
|
2116 |
Field f = fields[i].getField(); |
|
2117 |
throw new ClassCastException( |
|
2118 |
"cannot assign instance of " + |
|
2119 |
val.getClass().getName() + " to field " + |
|
2120 |
f.getDeclaringClass().getName() + "." + |
|
2121 |
f.getName() + " of type " + |
|
2122 |
f.getType().getName() + " in instance of " + |
|
2123 |
obj.getClass().getName()); |
|
2124 |
} |
|
30911
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2125 |
if (!dryRun) |
99e027461f4a
8071474: Better failure atomicity for default read object
chegar
parents:
29986
diff
changeset
|
2126 |
unsafe.putObject(obj, key, val); |
2 | 2127 |
break; |
2128 |
||
2129 |
default: |
|
2130 |
throw new InternalError(); |
|
2131 |
} |
|
2132 |
} |
|
2133 |
} |
|
2134 |
} |
|
2135 |
||
2136 |
/** |
|
2137 |
* Matches given set of serializable fields with serializable fields |
|
2138 |
* described by the given local class descriptor, and returns a |
|
2139 |
* FieldReflector instance capable of setting/getting values from the |
|
2140 |
* subset of fields that match (non-matching fields are treated as filler, |
|
2141 |
* for which get operations return default values and set operations |
|
2142 |
* discard given values). Throws InvalidClassException if unresolvable |
|
2143 |
* type conflicts exist between the two sets of fields. |
|
2144 |
*/ |
|
2145 |
private static FieldReflector getReflector(ObjectStreamField[] fields, |
|
2146 |
ObjectStreamClass localDesc) |
|
2147 |
throws InvalidClassException |
|
2148 |
{ |
|
2149 |
// class irrelevant if no fields |
|
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
2150 |
Class<?> cl = (localDesc != null && fields.length > 0) ? |
2 | 2151 |
localDesc.cl : null; |
2152 |
processQueue(Caches.reflectorsQueue, Caches.reflectors); |
|
2153 |
FieldReflectorKey key = new FieldReflectorKey(cl, fields, |
|
2154 |
Caches.reflectorsQueue); |
|
2155 |
Reference<?> ref = Caches.reflectors.get(key); |
|
2156 |
Object entry = null; |
|
2157 |
if (ref != null) { |
|
2158 |
entry = ref.get(); |
|
2159 |
} |
|
2160 |
EntryFuture future = null; |
|
2161 |
if (entry == null) { |
|
2162 |
EntryFuture newEntry = new EntryFuture(); |
|
7803
56bc97d69d93
6880112: Project Coin: Port JDK core library code to use diamond operator
smarks
parents:
7031
diff
changeset
|
2163 |
Reference<?> newRef = new SoftReference<>(newEntry); |
2 | 2164 |
do { |
2165 |
if (ref != null) { |
|
2166 |
Caches.reflectors.remove(key, ref); |
|
2167 |
} |
|
2168 |
ref = Caches.reflectors.putIfAbsent(key, newRef); |
|
2169 |
if (ref != null) { |
|
2170 |
entry = ref.get(); |
|
2171 |
} |
|
2172 |
} while (ref != null && entry == null); |
|
2173 |
if (entry == null) { |
|
2174 |
future = newEntry; |
|
2175 |
} |
|
2176 |
} |
|
2177 |
||
2178 |
if (entry instanceof FieldReflector) { // check common case first |
|
2179 |
return (FieldReflector) entry; |
|
2180 |
} else if (entry instanceof EntryFuture) { |
|
2181 |
entry = ((EntryFuture) entry).get(); |
|
2182 |
} else if (entry == null) { |
|
2183 |
try { |
|
2184 |
entry = new FieldReflector(matchFields(fields, localDesc)); |
|
2185 |
} catch (Throwable th) { |
|
2186 |
entry = th; |
|
2187 |
} |
|
2188 |
future.set(entry); |
|
29986
97167d851fc4
8078467: Update core libraries to use diamond with anonymous classes
darcy
parents:
25859
diff
changeset
|
2189 |
Caches.reflectors.put(key, new SoftReference<>(entry)); |
2 | 2190 |
} |
2191 |
||
2192 |
if (entry instanceof FieldReflector) { |
|
2193 |
return (FieldReflector) entry; |
|
2194 |
} else if (entry instanceof InvalidClassException) { |
|
2195 |
throw (InvalidClassException) entry; |
|
2196 |
} else if (entry instanceof RuntimeException) { |
|
2197 |
throw (RuntimeException) entry; |
|
2198 |
} else if (entry instanceof Error) { |
|
2199 |
throw (Error) entry; |
|
2200 |
} else { |
|
2201 |
throw new InternalError("unexpected entry: " + entry); |
|
2202 |
} |
|
2203 |
} |
|
2204 |
||
2205 |
/** |
|
2206 |
* FieldReflector cache lookup key. Keys are considered equal if they |
|
2207 |
* refer to the same class and equivalent field formats. |
|
2208 |
*/ |
|
2209 |
private static class FieldReflectorKey extends WeakReference<Class<?>> { |
|
2210 |
||
2211 |
private final String sigs; |
|
2212 |
private final int hash; |
|
2213 |
private final boolean nullClass; |
|
2214 |
||
4171
7edb512fdaa6
6895456: Eliminate dependency on java.io.ObjectStreamClass during boot
mchung
parents:
715
diff
changeset
|
2215 |
FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields, |
2 | 2216 |
ReferenceQueue<Class<?>> queue) |
2217 |
{ |
|
2218 |
super(cl, queue); |
|
2219 |
nullClass = (cl == null); |
|
2220 |
StringBuilder sbuf = new StringBuilder(); |
|
2221 |
for (int i = 0; i < fields.length; i++) { |
|
2222 |
ObjectStreamField f = fields[i]; |
|
2223 |
sbuf.append(f.getName()).append(f.getSignature()); |
|
2224 |
} |
|
2225 |
sigs = sbuf.toString(); |
|
2226 |
hash = System.identityHashCode(cl) + sigs.hashCode(); |
|
2227 |
} |
|
2228 |
||
2229 |
public int hashCode() { |
|
2230 |
return hash; |
|
2231 |
} |
|
2232 |
||
2233 |
public boolean equals(Object obj) { |
|
2234 |
if (obj == this) { |
|
2235 |
return true; |
|
2236 |
} |
|
2237 |
||
2238 |
if (obj instanceof FieldReflectorKey) { |
|
2239 |
FieldReflectorKey other = (FieldReflectorKey) obj; |
|
2240 |
Class<?> referent; |
|
2241 |
return (nullClass ? other.nullClass |
|
2242 |
: ((referent = get()) != null) && |
|
2243 |
(referent == other.get())) && |
|
2244 |
sigs.equals(other.sigs); |
|
2245 |
} else { |
|
2246 |
return false; |
|
2247 |
} |
|
2248 |
} |
|
2249 |
} |
|
2250 |
||
2251 |
/** |
|
2252 |
* Matches given set of serializable fields with serializable fields |
|
2253 |
* obtained from the given local class descriptor (which contain bindings |
|
2254 |
* to reflective Field objects). Returns list of ObjectStreamFields in |
|
2255 |
* which each ObjectStreamField whose signature matches that of a local |
|
2256 |
* field contains a Field object for that field; unmatched |
|
2257 |
* ObjectStreamFields contain null Field objects. Shared/unshared settings |
|
2258 |
* of the returned ObjectStreamFields also reflect those of matched local |
|
2259 |
* ObjectStreamFields. Throws InvalidClassException if unresolvable type |
|
2260 |
* conflicts exist between the two sets of fields. |
|
2261 |
*/ |
|
2262 |
private static ObjectStreamField[] matchFields(ObjectStreamField[] fields, |
|
2263 |
ObjectStreamClass localDesc) |
|
2264 |
throws InvalidClassException |
|
2265 |
{ |
|
2266 |
ObjectStreamField[] localFields = (localDesc != null) ? |
|
2267 |
localDesc.fields : NO_FIELDS; |
|
2268 |
||
2269 |
/* |
|
2270 |
* Even if fields == localFields, we cannot simply return localFields |
|
2271 |
* here. In previous implementations of serialization, |
|
2272 |
* ObjectStreamField.getType() returned Object.class if the |
|
2273 |
* ObjectStreamField represented a non-primitive field and belonged to |
|
2274 |
* a non-local class descriptor. To preserve this (questionable) |
|
2275 |
* behavior, the ObjectStreamField instances returned by matchFields |
|
2276 |
* cannot report non-primitive types other than Object.class; hence |
|
2277 |
* localFields cannot be returned directly. |
|
2278 |
*/ |
|
2279 |
||
2280 |
ObjectStreamField[] matches = new ObjectStreamField[fields.length]; |
|
2281 |
for (int i = 0; i < fields.length; i++) { |
|
2282 |
ObjectStreamField f = fields[i], m = null; |
|
2283 |
for (int j = 0; j < localFields.length; j++) { |
|
2284 |
ObjectStreamField lf = localFields[j]; |
|
2285 |
if (f.getName().equals(lf.getName())) { |
|
2286 |
if ((f.isPrimitive() || lf.isPrimitive()) && |
|
2287 |
f.getTypeCode() != lf.getTypeCode()) |
|
2288 |
{ |
|
2289 |
throw new InvalidClassException(localDesc.name, |
|
2290 |
"incompatible types for field " + f.getName()); |
|
2291 |
} |
|
2292 |
if (lf.getField() != null) { |
|
2293 |
m = new ObjectStreamField( |
|
2294 |
lf.getField(), lf.isUnshared(), false); |
|
2295 |
} else { |
|
2296 |
m = new ObjectStreamField( |
|
2297 |
lf.getName(), lf.getSignature(), lf.isUnshared()); |
|
2298 |
} |
|
2299 |
} |
|
2300 |
} |
|
2301 |
if (m == null) { |
|
2302 |
m = new ObjectStreamField( |
|
2303 |
f.getName(), f.getSignature(), false); |
|
2304 |
} |
|
2305 |
m.setOffset(f.getOffset()); |
|
2306 |
matches[i] = m; |
|
2307 |
} |
|
2308 |
return matches; |
|
2309 |
} |
|
2310 |
||
2311 |
/** |
|
2312 |
* Removes from the specified map any keys that have been enqueued |
|
2313 |
* on the specified reference queue. |
|
2314 |
*/ |
|
2315 |
static void processQueue(ReferenceQueue<Class<?>> queue, |
|
2316 |
ConcurrentMap<? extends |
|
2317 |
WeakReference<Class<?>>, ?> map) |
|
2318 |
{ |
|
2319 |
Reference<? extends Class<?>> ref; |
|
2320 |
while((ref = queue.poll()) != null) { |
|
2321 |
map.remove(ref); |
|
2322 |
} |
|
2323 |
} |
|
2324 |
||
2325 |
/** |
|
2326 |
* Weak key for Class objects. |
|
2327 |
* |
|
2328 |
**/ |
|
2329 |
static class WeakClassKey extends WeakReference<Class<?>> { |
|
2330 |
/** |
|
2331 |
* saved value of the referent's identity hash code, to maintain |
|
2332 |
* a consistent hash code after the referent has been cleared |
|
2333 |
*/ |
|
2334 |
private final int hash; |
|
2335 |
||
2336 |
/** |
|
2337 |
* Create a new WeakClassKey to the given object, registered |
|
2338 |
* with a queue. |
|
2339 |
*/ |
|
2340 |
WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { |
|
2341 |
super(cl, refQueue); |
|
2342 |
hash = System.identityHashCode(cl); |
|
2343 |
} |
|
2344 |
||
2345 |
/** |
|
2346 |
* Returns the identity hash code of the original referent. |
|
2347 |
*/ |
|
2348 |
public int hashCode() { |
|
2349 |
return hash; |
|
2350 |
} |
|
2351 |
||
2352 |
/** |
|
2353 |
* Returns true if the given object is this identical |
|
2354 |
* WeakClassKey instance, or, if this object's referent has not |
|
2355 |
* been cleared, if the given object is another WeakClassKey |
|
2356 |
* instance with the identical non-null referent as this one. |
|
2357 |
*/ |
|
2358 |
public boolean equals(Object obj) { |
|
2359 |
if (obj == this) { |
|
2360 |
return true; |
|
2361 |
} |
|
2362 |
||
2363 |
if (obj instanceof WeakClassKey) { |
|
2364 |
Object referent = get(); |
|
2365 |
return (referent != null) && |
|
2366 |
(referent == ((WeakClassKey) obj).get()); |
|
2367 |
} else { |
|
2368 |
return false; |
|
2369 |
} |
|
2370 |
} |
|
2371 |
} |
|
2372 |
} |