Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/management/MBeanInfo.java
38829 views
1
/*
2
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.management;
27
28
import java.io.IOException;
29
import java.io.StreamCorruptedException;
30
import java.io.Serializable;
31
import java.io.ObjectOutputStream;
32
import java.io.ObjectInputStream;
33
import java.lang.reflect.Method;
34
import java.util.Arrays;
35
import java.util.Map;
36
import java.util.WeakHashMap;
37
import java.security.AccessController;
38
import java.security.PrivilegedAction;
39
import java.util.Objects;
40
41
import static javax.management.ImmutableDescriptor.nonNullDescriptor;
42
43
/**
44
* <p>Describes the management interface exposed by an MBean; that is,
45
* the set of attributes and operations which are available for
46
* management operations. Instances of this class are immutable.
47
* Subclasses may be mutable but this is not recommended.</p>
48
*
49
* <p id="info-changed">Usually the {@code MBeanInfo} for any given MBean does
50
* not change over the lifetime of that MBean. Dynamic MBeans can change their
51
* {@code MBeanInfo} and in that case it is recommended that they emit a {@link
52
* Notification} with a {@linkplain Notification#getType() type} of {@code
53
* "jmx.mbean.info.changed"} and a {@linkplain Notification#getUserData()
54
* userData} that is the new {@code MBeanInfo}. This is not required, but
55
* provides a conventional way for clients of the MBean to discover the change.
56
* See also the <a href="Descriptor.html#immutableInfo">immutableInfo</a> and
57
* <a href="Descriptor.html#infoTimeout">infoTimeout</a> fields in the {@code
58
* MBeanInfo} {@link Descriptor}.</p>
59
*
60
* <p>The contents of the <code>MBeanInfo</code> for a Dynamic MBean
61
* are determined by its {@link DynamicMBean#getMBeanInfo
62
* getMBeanInfo()} method. This includes Open MBeans and Model
63
* MBeans, which are kinds of Dynamic MBeans.</p>
64
*
65
* <p>The contents of the <code>MBeanInfo</code> for a Standard MBean
66
* are determined by the MBean server as follows:</p>
67
*
68
* <ul>
69
*
70
* <li>{@link #getClassName()} returns the Java class name of the MBean
71
* object;
72
*
73
* <li>{@link #getConstructors()} returns the list of all public
74
* constructors in that object;
75
*
76
* <li>{@link #getAttributes()} returns the list of all attributes
77
* whose existence is deduced from the presence in the MBean interface
78
* of a <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
79
* <code>set<i>Name</i></code> method that conforms to the conventions
80
* for Standard MBeans;
81
*
82
* <li>{@link #getOperations()} returns the list of all methods in
83
* the MBean interface that do not represent attributes;
84
*
85
* <li>{@link #getNotifications()} returns an empty array if the MBean
86
* does not implement the {@link NotificationBroadcaster} interface,
87
* otherwise the result of calling {@link
88
* NotificationBroadcaster#getNotificationInfo()} on it;
89
*
90
* <li>{@link #getDescriptor()} returns a descriptor containing the contents
91
* of any descriptor annotations in the MBean interface (see
92
* {@link DescriptorKey &#64;DescriptorKey}).
93
*
94
* </ul>
95
*
96
* <p>The description returned by {@link #getDescription()} and the
97
* descriptions of the contained attributes and operations are not specified.</p>
98
*
99
* <p>The remaining details of the <code>MBeanInfo</code> for a
100
* Standard MBean are not specified. This includes the description of
101
* any contained constructors, and notifications; the names
102
* of parameters to constructors and operations; and the descriptions of
103
* constructor parameters.</p>
104
*
105
* @since 1.5
106
*/
107
public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
108
109
/* Serial version */
110
static final long serialVersionUID = -6451021435135161911L;
111
112
/**
113
* @serial The Descriptor for the MBean. This field
114
* can be null, which is equivalent to an empty Descriptor.
115
*/
116
private transient Descriptor descriptor;
117
118
/**
119
* @serial The human readable description of the class.
120
*/
121
private final String description;
122
123
/**
124
* @serial The MBean qualified name.
125
*/
126
private final String className;
127
128
/**
129
* @serial The MBean attribute descriptors.
130
*/
131
private final MBeanAttributeInfo[] attributes;
132
133
/**
134
* @serial The MBean operation descriptors.
135
*/
136
private final MBeanOperationInfo[] operations;
137
138
/**
139
* @serial The MBean constructor descriptors.
140
*/
141
private final MBeanConstructorInfo[] constructors;
142
143
/**
144
* @serial The MBean notification descriptors.
145
*/
146
private final MBeanNotificationInfo[] notifications;
147
148
private transient int hashCode;
149
150
/**
151
* <p>True if this class is known not to override the array-valued
152
* getters of MBeanInfo. Obviously true for MBeanInfo itself, and true
153
* for a subclass where we succeed in reflecting on the methods
154
* and discover they are not overridden.</p>
155
*
156
* <p>The purpose of this variable is to avoid cloning the arrays
157
* when doing operations like {@link #equals} where we know they
158
* will not be changed. If a subclass overrides a getter, we
159
* cannot access the corresponding array directly.</p>
160
*/
161
private final transient boolean arrayGettersSafe;
162
163
/**
164
* Constructs an <CODE>MBeanInfo</CODE>.
165
*
166
* @param className The name of the Java class of the MBean described
167
* by this <CODE>MBeanInfo</CODE>. This value may be any
168
* syntactically legal Java class name. It does not have to be a
169
* Java class known to the MBean server or to the MBean's
170
* ClassLoader. If it is a Java class known to the MBean's
171
* ClassLoader, it is recommended but not required that the
172
* class's public methods include those that would appear in a
173
* Standard MBean implementing the attributes and operations in
174
* this MBeanInfo.
175
* @param description A human readable description of the MBean (optional).
176
* @param attributes The list of exposed attributes of the MBean.
177
* This may be null with the same effect as a zero-length array.
178
* @param constructors The list of public constructors of the
179
* MBean. This may be null with the same effect as a zero-length
180
* array.
181
* @param operations The list of operations of the MBean. This
182
* may be null with the same effect as a zero-length array.
183
* @param notifications The list of notifications emitted. This
184
* may be null with the same effect as a zero-length array.
185
*/
186
public MBeanInfo(String className,
187
String description,
188
MBeanAttributeInfo[] attributes,
189
MBeanConstructorInfo[] constructors,
190
MBeanOperationInfo[] operations,
191
MBeanNotificationInfo[] notifications)
192
throws IllegalArgumentException {
193
this(className, description, attributes, constructors, operations,
194
notifications, null);
195
}
196
197
/**
198
* Constructs an <CODE>MBeanInfo</CODE>.
199
*
200
* @param className The name of the Java class of the MBean described
201
* by this <CODE>MBeanInfo</CODE>. This value may be any
202
* syntactically legal Java class name. It does not have to be a
203
* Java class known to the MBean server or to the MBean's
204
* ClassLoader. If it is a Java class known to the MBean's
205
* ClassLoader, it is recommended but not required that the
206
* class's public methods include those that would appear in a
207
* Standard MBean implementing the attributes and operations in
208
* this MBeanInfo.
209
* @param description A human readable description of the MBean (optional).
210
* @param attributes The list of exposed attributes of the MBean.
211
* This may be null with the same effect as a zero-length array.
212
* @param constructors The list of public constructors of the
213
* MBean. This may be null with the same effect as a zero-length
214
* array.
215
* @param operations The list of operations of the MBean. This
216
* may be null with the same effect as a zero-length array.
217
* @param notifications The list of notifications emitted. This
218
* may be null with the same effect as a zero-length array.
219
* @param descriptor The descriptor for the MBean. This may be null
220
* which is equivalent to an empty descriptor.
221
*
222
* @since 1.6
223
*/
224
public MBeanInfo(String className,
225
String description,
226
MBeanAttributeInfo[] attributes,
227
MBeanConstructorInfo[] constructors,
228
MBeanOperationInfo[] operations,
229
MBeanNotificationInfo[] notifications,
230
Descriptor descriptor)
231
throws IllegalArgumentException {
232
233
this.className = className;
234
235
this.description = description;
236
237
if (attributes == null)
238
attributes = MBeanAttributeInfo.NO_ATTRIBUTES;
239
this.attributes = attributes;
240
241
if (operations == null)
242
operations = MBeanOperationInfo.NO_OPERATIONS;
243
this.operations = operations;
244
245
if (constructors == null)
246
constructors = MBeanConstructorInfo.NO_CONSTRUCTORS;
247
this.constructors = constructors;
248
249
if (notifications == null)
250
notifications = MBeanNotificationInfo.NO_NOTIFICATIONS;
251
this.notifications = notifications;
252
253
if (descriptor == null)
254
descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
255
this.descriptor = descriptor;
256
257
this.arrayGettersSafe =
258
arrayGettersSafe(this.getClass(), MBeanInfo.class);
259
}
260
261
/**
262
* <p>Returns a shallow clone of this instance.
263
* The clone is obtained by simply calling <tt>super.clone()</tt>,
264
* thus calling the default native shallow cloning mechanism
265
* implemented by <tt>Object.clone()</tt>.
266
* No deeper cloning of any internal field is made.</p>
267
*
268
* <p>Since this class is immutable, the clone method is chiefly of
269
* interest to subclasses.</p>
270
*/
271
@Override
272
public Object clone () {
273
try {
274
return super.clone() ;
275
} catch (CloneNotSupportedException e) {
276
// should not happen as this class is cloneable
277
return null;
278
}
279
}
280
281
282
/**
283
* Returns the name of the Java class of the MBean described by
284
* this <CODE>MBeanInfo</CODE>.
285
*
286
* @return the class name.
287
*/
288
public String getClassName() {
289
return className;
290
}
291
292
/**
293
* Returns a human readable description of the MBean.
294
*
295
* @return the description.
296
*/
297
public String getDescription() {
298
return description;
299
}
300
301
/**
302
* Returns the list of attributes exposed for management.
303
* Each attribute is described by an <CODE>MBeanAttributeInfo</CODE> object.
304
*
305
* The returned array is a shallow copy of the internal array,
306
* which means that it is a copy of the internal array of
307
* references to the <CODE>MBeanAttributeInfo</CODE> objects
308
* but that each referenced <CODE>MBeanAttributeInfo</CODE> object is not copied.
309
*
310
* @return An array of <CODE>MBeanAttributeInfo</CODE> objects.
311
*/
312
public MBeanAttributeInfo[] getAttributes() {
313
MBeanAttributeInfo[] as = nonNullAttributes();
314
if (as.length == 0)
315
return as;
316
else
317
return as.clone();
318
}
319
320
private MBeanAttributeInfo[] fastGetAttributes() {
321
if (arrayGettersSafe)
322
return nonNullAttributes();
323
else
324
return getAttributes();
325
}
326
327
/**
328
* Return the value of the attributes field, or an empty array if
329
* the field is null. This can't happen with a
330
* normally-constructed instance of this class, but can if the
331
* instance was deserialized from another implementation that
332
* allows the field to be null. It would be simpler if we enforced
333
* the class invariant that these fields cannot be null by writing
334
* a readObject() method, but that would require us to define the
335
* various array fields as non-final, which is annoying because
336
* conceptually they are indeed final.
337
*/
338
private MBeanAttributeInfo[] nonNullAttributes() {
339
return (attributes == null) ?
340
MBeanAttributeInfo.NO_ATTRIBUTES : attributes;
341
}
342
343
/**
344
* Returns the list of operations of the MBean.
345
* Each operation is described by an <CODE>MBeanOperationInfo</CODE> object.
346
*
347
* The returned array is a shallow copy of the internal array,
348
* which means that it is a copy of the internal array of
349
* references to the <CODE>MBeanOperationInfo</CODE> objects
350
* but that each referenced <CODE>MBeanOperationInfo</CODE> object is not copied.
351
*
352
* @return An array of <CODE>MBeanOperationInfo</CODE> objects.
353
*/
354
public MBeanOperationInfo[] getOperations() {
355
MBeanOperationInfo[] os = nonNullOperations();
356
if (os.length == 0)
357
return os;
358
else
359
return os.clone();
360
}
361
362
private MBeanOperationInfo[] fastGetOperations() {
363
if (arrayGettersSafe)
364
return nonNullOperations();
365
else
366
return getOperations();
367
}
368
369
private MBeanOperationInfo[] nonNullOperations() {
370
return (operations == null) ?
371
MBeanOperationInfo.NO_OPERATIONS : operations;
372
}
373
374
/**
375
* <p>Returns the list of the public constructors of the MBean.
376
* Each constructor is described by an
377
* <CODE>MBeanConstructorInfo</CODE> object.</p>
378
*
379
* <p>The returned array is a shallow copy of the internal array,
380
* which means that it is a copy of the internal array of
381
* references to the <CODE>MBeanConstructorInfo</CODE> objects but
382
* that each referenced <CODE>MBeanConstructorInfo</CODE> object
383
* is not copied.</p>
384
*
385
* <p>The returned list is not necessarily exhaustive. That is,
386
* the MBean may have a public constructor that is not in the
387
* list. In this case, the MBean server can construct another
388
* instance of this MBean's class using that constructor, even
389
* though it is not listed here.</p>
390
*
391
* @return An array of <CODE>MBeanConstructorInfo</CODE> objects.
392
*/
393
public MBeanConstructorInfo[] getConstructors() {
394
MBeanConstructorInfo[] cs = nonNullConstructors();
395
if (cs.length == 0)
396
return cs;
397
else
398
return cs.clone();
399
}
400
401
private MBeanConstructorInfo[] fastGetConstructors() {
402
if (arrayGettersSafe)
403
return nonNullConstructors();
404
else
405
return getConstructors();
406
}
407
408
private MBeanConstructorInfo[] nonNullConstructors() {
409
return (constructors == null) ?
410
MBeanConstructorInfo.NO_CONSTRUCTORS : constructors;
411
}
412
413
/**
414
* Returns the list of the notifications emitted by the MBean.
415
* Each notification is described by an <CODE>MBeanNotificationInfo</CODE> object.
416
*
417
* The returned array is a shallow copy of the internal array,
418
* which means that it is a copy of the internal array of
419
* references to the <CODE>MBeanNotificationInfo</CODE> objects
420
* but that each referenced <CODE>MBeanNotificationInfo</CODE> object is not copied.
421
*
422
* @return An array of <CODE>MBeanNotificationInfo</CODE> objects.
423
*/
424
public MBeanNotificationInfo[] getNotifications() {
425
MBeanNotificationInfo[] ns = nonNullNotifications();
426
if (ns.length == 0)
427
return ns;
428
else
429
return ns.clone();
430
}
431
432
private MBeanNotificationInfo[] fastGetNotifications() {
433
if (arrayGettersSafe)
434
return nonNullNotifications();
435
else
436
return getNotifications();
437
}
438
439
private MBeanNotificationInfo[] nonNullNotifications() {
440
return (notifications == null) ?
441
MBeanNotificationInfo.NO_NOTIFICATIONS : notifications;
442
}
443
444
/**
445
* Get the descriptor of this MBeanInfo. Changing the returned value
446
* will have no affect on the original descriptor.
447
*
448
* @return a descriptor that is either immutable or a copy of the original.
449
*
450
* @since 1.6
451
*/
452
public Descriptor getDescriptor() {
453
return (Descriptor) nonNullDescriptor(descriptor).clone();
454
}
455
456
@Override
457
public String toString() {
458
return
459
getClass().getName() + "[" +
460
"description=" + getDescription() + ", " +
461
"attributes=" + Arrays.asList(fastGetAttributes()) + ", " +
462
"constructors=" + Arrays.asList(fastGetConstructors()) + ", " +
463
"operations=" + Arrays.asList(fastGetOperations()) + ", " +
464
"notifications=" + Arrays.asList(fastGetNotifications()) + ", " +
465
"descriptor=" + getDescriptor() +
466
"]";
467
}
468
469
/**
470
* <p>Compare this MBeanInfo to another. Two MBeanInfo objects
471
* are equal if and only if they return equal values for {@link
472
* #getClassName()}, for {@link #getDescription()}, and for
473
* {@link #getDescriptor()}, and the
474
* arrays returned by the two objects for {@link
475
* #getAttributes()}, {@link #getOperations()}, {@link
476
* #getConstructors()}, and {@link #getNotifications()} are
477
* pairwise equal. Here "equal" means {@link
478
* Object#equals(Object)}, not identity.</p>
479
*
480
* <p>If two MBeanInfo objects return the same values in one of
481
* their arrays but in a different order then they are not equal.</p>
482
*
483
* @param o the object to compare to.
484
*
485
* @return true if and only if <code>o</code> is an MBeanInfo that is equal
486
* to this one according to the rules above.
487
*/
488
@Override
489
public boolean equals(Object o) {
490
if (o == this)
491
return true;
492
if (!(o instanceof MBeanInfo))
493
return false;
494
MBeanInfo p = (MBeanInfo) o;
495
if (!isEqual(getClassName(), p.getClassName()) ||
496
!isEqual(getDescription(), p.getDescription()) ||
497
!getDescriptor().equals(p.getDescriptor())) {
498
return false;
499
}
500
501
return
502
(Arrays.equals(p.fastGetAttributes(), fastGetAttributes()) &&
503
Arrays.equals(p.fastGetOperations(), fastGetOperations()) &&
504
Arrays.equals(p.fastGetConstructors(), fastGetConstructors()) &&
505
Arrays.equals(p.fastGetNotifications(), fastGetNotifications()));
506
}
507
508
@Override
509
public int hashCode() {
510
/* Since computing the hashCode is quite expensive, we cache it.
511
If by some terrible misfortune the computed value is 0, the
512
caching won't work and we will recompute it every time.
513
514
We don't bother synchronizing, because, at worst, n different
515
threads will compute the same hashCode at the same time. */
516
if (hashCode != 0)
517
return hashCode;
518
519
hashCode = Objects.hash(getClassName(), getDescriptor())
520
^ Arrays.hashCode(fastGetAttributes())
521
^ Arrays.hashCode(fastGetOperations())
522
^ Arrays.hashCode(fastGetConstructors())
523
^ Arrays.hashCode(fastGetNotifications());
524
525
return hashCode;
526
}
527
528
/**
529
* Cached results of previous calls to arrayGettersSafe. This is
530
* a WeakHashMap so that we don't prevent a class from being
531
* garbage collected just because we know whether it's immutable.
532
*/
533
private static final Map<Class<?>, Boolean> arrayGettersSafeMap =
534
new WeakHashMap<Class<?>, Boolean>();
535
536
/**
537
* Return true if <code>subclass</code> is known to preserve the
538
* immutability of <code>immutableClass</code>. The class
539
* <code>immutableClass</code> is a reference class that is known
540
* to be immutable. The subclass <code>subclass</code> is
541
* considered immutable if it does not override any public method
542
* of <code>immutableClass</code> whose name begins with "get".
543
* This is obviously not an infallible test for immutability,
544
* but it works for the public interfaces of the MBean*Info classes.
545
*/
546
static boolean arrayGettersSafe(Class<?> subclass, Class<?> immutableClass) {
547
if (subclass == immutableClass)
548
return true;
549
synchronized (arrayGettersSafeMap) {
550
Boolean safe = arrayGettersSafeMap.get(subclass);
551
if (safe == null) {
552
try {
553
ArrayGettersSafeAction action =
554
new ArrayGettersSafeAction(subclass, immutableClass);
555
safe = AccessController.doPrivileged(action);
556
} catch (Exception e) { // e.g. SecurityException
557
/* We don't know, so we assume it isn't. */
558
safe = false;
559
}
560
arrayGettersSafeMap.put(subclass, safe);
561
}
562
return safe;
563
}
564
}
565
566
/*
567
* The PrivilegedAction stuff is probably overkill. We can be
568
* pretty sure the caller does have the required privileges -- a
569
* JMX user that can't do reflection can't even use Standard
570
* MBeans! But there's probably a performance gain by not having
571
* to check the whole call stack.
572
*/
573
private static class ArrayGettersSafeAction
574
implements PrivilegedAction<Boolean> {
575
576
private final Class<?> subclass;
577
private final Class<?> immutableClass;
578
579
ArrayGettersSafeAction(Class<?> subclass, Class<?> immutableClass) {
580
this.subclass = subclass;
581
this.immutableClass = immutableClass;
582
}
583
584
public Boolean run() {
585
Method[] methods = immutableClass.getMethods();
586
for (int i = 0; i < methods.length; i++) {
587
Method method = methods[i];
588
String methodName = method.getName();
589
if (methodName.startsWith("get") &&
590
method.getParameterTypes().length == 0 &&
591
method.getReturnType().isArray()) {
592
try {
593
Method submethod =
594
subclass.getMethod(methodName);
595
if (!submethod.equals(method))
596
return false;
597
} catch (NoSuchMethodException e) {
598
return false;
599
}
600
}
601
}
602
return true;
603
}
604
}
605
606
private static boolean isEqual(String s1, String s2) {
607
boolean ret;
608
609
if (s1 == null) {
610
ret = (s2 == null);
611
} else {
612
ret = s1.equals(s2);
613
}
614
615
return ret;
616
}
617
618
/**
619
* Serializes an {@link MBeanInfo} to an {@link ObjectOutputStream}.
620
* @serialData
621
* For compatibility reasons, an object of this class is serialized as follows.
622
* <p>
623
* The method {@link ObjectOutputStream#defaultWriteObject defaultWriteObject()}
624
* is called first to serialize the object except the field {@code descriptor}
625
* which is declared as transient. The field {@code descriptor} is serialized
626
* as follows:
627
* <ul>
628
* <li> If {@code descriptor} is an instance of the class
629
* {@link ImmutableDescriptor}, the method {@link ObjectOutputStream#write
630
* write(int val)} is called to write a byte with the value {@code 1},
631
* then the method {@link ObjectOutputStream#writeObject writeObject(Object obj)}
632
* is called twice to serialize the field names and the field values of the
633
* {@code descriptor}, respectively as a {@code String[]} and an
634
* {@code Object[]};</li>
635
* <li> Otherwise, the method {@link ObjectOutputStream#write write(int val)}
636
* is called to write a byte with the value {@code 0}, then the method
637
* {@link ObjectOutputStream#writeObject writeObject(Object obj)} is called
638
* to serialize the field {@code descriptor} directly.
639
* </ul>
640
*
641
* @since 1.6
642
*/
643
private void writeObject(ObjectOutputStream out) throws IOException {
644
out.defaultWriteObject();
645
646
if (descriptor.getClass() == ImmutableDescriptor.class) {
647
out.write(1);
648
649
final String[] names = descriptor.getFieldNames();
650
651
out.writeObject(names);
652
out.writeObject(descriptor.getFieldValues(names));
653
} else {
654
out.write(0);
655
656
out.writeObject(descriptor);
657
}
658
}
659
660
/**
661
* Deserializes an {@link MBeanInfo} from an {@link ObjectInputStream}.
662
* @serialData
663
* For compatibility reasons, an object of this class is deserialized as follows.
664
* <p>
665
* The method {@link ObjectInputStream#defaultReadObject defaultReadObject()}
666
* is called first to deserialize the object except the field
667
* {@code descriptor}, which is not serialized in the default way. Then the method
668
* {@link ObjectInputStream#read read()} is called to read a byte, the field
669
* {@code descriptor} is deserialized according to the value of the byte value:
670
* <ul>
671
* <li>1. The method {@link ObjectInputStream#readObject readObject()}
672
* is called twice to obtain the field names (a {@code String[]}) and
673
* the field values (a {@code Object[]}) of the {@code descriptor}.
674
* The two obtained values then are used to construct
675
* an {@link ImmutableDescriptor} instance for the field
676
* {@code descriptor};</li>
677
* <li>0. The value for the field {@code descriptor} is obtained directly
678
* by calling the method {@link ObjectInputStream#readObject readObject()}.
679
* If the obtained value is null, the field {@code descriptor} is set to
680
* {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR};</li>
681
* <li>-1. This means that there is no byte to read and that the object is from
682
* an earlier version of the JMX API. The field {@code descriptor} is set to
683
* {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR}.</li>
684
* <li>Any other value. A {@link StreamCorruptedException} is thrown.</li>
685
* </ul>
686
*
687
* @since 1.6
688
*/
689
690
private void readObject(ObjectInputStream in)
691
throws IOException, ClassNotFoundException {
692
693
in.defaultReadObject();
694
695
switch (in.read()) {
696
case 1:
697
final String[] names = (String[])in.readObject();
698
699
final Object[] values = (Object[]) in.readObject();
700
descriptor = (names.length == 0) ?
701
ImmutableDescriptor.EMPTY_DESCRIPTOR :
702
new ImmutableDescriptor(names, values);
703
704
break;
705
case 0:
706
descriptor = (Descriptor)in.readObject();
707
708
if (descriptor == null) {
709
descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
710
}
711
712
break;
713
case -1: // from an earlier version of the JMX API
714
descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
715
716
break;
717
default:
718
throw new StreamCorruptedException("Got unexpected byte.");
719
}
720
}
721
}
722
723