Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.management/share/classes/javax/management/MBeanInfo.java
41154 views
1
/*
2
* Copyright (c) 1999, 2021, 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} 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} 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} 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}.
165
*
166
* @param className The name of the Java class of the MBean described
167
* by this {@code MBeanInfo}. 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}.
199
*
200
* @param className The name of the Java class of the MBean described
201
* by this {@code MBeanInfo}. 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 {@code super.clone()},
264
* thus calling the default native shallow cloning mechanism
265
* implemented by {@code Object.clone()}.
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}.
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} 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} objects
308
* but that each referenced {@code MBeanAttributeInfo} object is not copied.
309
*
310
* @return An array of {@code MBeanAttributeInfo} 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} 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} objects
350
* but that each referenced {@code MBeanOperationInfo} object is not copied.
351
*
352
* @return An array of {@code MBeanOperationInfo} 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} 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} objects but
382
* that each referenced {@code MBeanConstructorInfo} 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} 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} 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} objects
420
* but that each referenced {@code MBeanNotificationInfo} object is not copied.
421
*
422
* @return An array of {@code MBeanNotificationInfo} 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} 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} is known to preserve the
538
* immutability of {@code immutableClass}. The class
539
* {@code immutableClass} is a reference class that is known
540
* to be immutable. The subclass {@code subclass} is
541
* considered immutable if it does not override any public method
542
* of {@code immutableClass} 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
@SuppressWarnings("removal")
547
static boolean arrayGettersSafe(Class<?> subclass, Class<?> immutableClass) {
548
if (subclass == immutableClass)
549
return true;
550
synchronized (arrayGettersSafeMap) {
551
Boolean safe = arrayGettersSafeMap.get(subclass);
552
if (safe == null) {
553
try {
554
ArrayGettersSafeAction action =
555
new ArrayGettersSafeAction(subclass, immutableClass);
556
safe = AccessController.doPrivileged(action);
557
} catch (Exception e) { // e.g. SecurityException
558
/* We don't know, so we assume it isn't. */
559
safe = false;
560
}
561
arrayGettersSafeMap.put(subclass, safe);
562
}
563
return safe;
564
}
565
}
566
567
/*
568
* The PrivilegedAction stuff is probably overkill. We can be
569
* pretty sure the caller does have the required privileges -- a
570
* JMX user that can't do reflection can't even use Standard
571
* MBeans! But there's probably a performance gain by not having
572
* to check the whole call stack.
573
*/
574
private static class ArrayGettersSafeAction
575
implements PrivilegedAction<Boolean> {
576
577
private final Class<?> subclass;
578
private final Class<?> immutableClass;
579
580
ArrayGettersSafeAction(Class<?> subclass, Class<?> immutableClass) {
581
this.subclass = subclass;
582
this.immutableClass = immutableClass;
583
}
584
585
public Boolean run() {
586
Method[] methods = immutableClass.getMethods();
587
for (int i = 0; i < methods.length; i++) {
588
Method method = methods[i];
589
String methodName = method.getName();
590
if (methodName.startsWith("get") &&
591
method.getParameterTypes().length == 0 &&
592
method.getReturnType().isArray()) {
593
try {
594
Method submethod =
595
subclass.getMethod(methodName);
596
if (!submethod.equals(method))
597
return false;
598
} catch (NoSuchMethodException e) {
599
return false;
600
}
601
}
602
}
603
return true;
604
}
605
}
606
607
private static boolean isEqual(String s1, String s2) {
608
boolean ret;
609
610
if (s1 == null) {
611
ret = (s2 == null);
612
} else {
613
ret = s1.equals(s2);
614
}
615
616
return ret;
617
}
618
619
/**
620
* Serializes an {@link MBeanInfo} to an {@link ObjectOutputStream}.
621
* @serialData
622
* For compatibility reasons, an object of this class is serialized as follows.
623
* <p>
624
* The method {@link ObjectOutputStream#defaultWriteObject defaultWriteObject()}
625
* is called first to serialize the object except the field {@code descriptor}
626
* which is declared as transient. The field {@code descriptor} is serialized
627
* as follows:
628
* <ul>
629
* <li> If {@code descriptor} is an instance of the class
630
* {@link ImmutableDescriptor}, the method {@link ObjectOutputStream#write
631
* write(int val)} is called to write a byte with the value {@code 1},
632
* then the method {@link ObjectOutputStream#writeObject writeObject(Object obj)}
633
* is called twice to serialize the field names and the field values of the
634
* {@code descriptor}, respectively as a {@code String[]} and an
635
* {@code Object[]};</li>
636
* <li> Otherwise, the method {@link ObjectOutputStream#write write(int val)}
637
* is called to write a byte with the value {@code 0}, then the method
638
* {@link ObjectOutputStream#writeObject writeObject(Object obj)} is called
639
* to serialize the field {@code descriptor} directly.
640
* </ul>
641
*
642
* @since 1.6
643
*/
644
private void writeObject(ObjectOutputStream out) throws IOException {
645
out.defaultWriteObject();
646
647
if (descriptor.getClass() == ImmutableDescriptor.class) {
648
out.write(1);
649
650
final String[] names = descriptor.getFieldNames();
651
652
out.writeObject(names);
653
out.writeObject(descriptor.getFieldValues(names));
654
} else {
655
out.write(0);
656
657
out.writeObject(descriptor);
658
}
659
}
660
661
/**
662
* Deserializes an {@link MBeanInfo} from an {@link ObjectInputStream}.
663
* @serialData
664
* For compatibility reasons, an object of this class is deserialized as follows.
665
* <p>
666
* The method {@link ObjectInputStream#defaultReadObject defaultReadObject()}
667
* is called first to deserialize the object except the field
668
* {@code descriptor}, which is not serialized in the default way. Then the method
669
* {@link ObjectInputStream#read read()} is called to read a byte, the field
670
* {@code descriptor} is deserialized according to the value of the byte value:
671
* <ul>
672
* <li>1. The method {@link ObjectInputStream#readObject readObject()}
673
* is called twice to obtain the field names (a {@code String[]}) and
674
* the field values (an {@code Object[]}) of the {@code descriptor}.
675
* The two obtained values then are used to construct
676
* an {@link ImmutableDescriptor} instance for the field
677
* {@code descriptor};</li>
678
* <li>0. The value for the field {@code descriptor} is obtained directly
679
* by calling the method {@link ObjectInputStream#readObject readObject()}.
680
* If the obtained value is null, the field {@code descriptor} is set to
681
* {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR};</li>
682
* <li>-1. This means that there is no byte to read and that the object is from
683
* an earlier version of the JMX API. The field {@code descriptor} is set to
684
* {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR}.</li>
685
* <li>Any other value. A {@link StreamCorruptedException} is thrown.</li>
686
* </ul>
687
*
688
* @since 1.6
689
*/
690
691
private void readObject(ObjectInputStream in)
692
throws IOException, ClassNotFoundException {
693
694
in.defaultReadObject();
695
696
switch (in.read()) {
697
case 1:
698
final String[] names = (String[])in.readObject();
699
700
final Object[] values = (Object[]) in.readObject();
701
descriptor = (names.length == 0) ?
702
ImmutableDescriptor.EMPTY_DESCRIPTOR :
703
new ImmutableDescriptor(names, values);
704
705
break;
706
case 0:
707
descriptor = (Descriptor)in.readObject();
708
709
if (descriptor == null) {
710
descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
711
}
712
713
break;
714
case -1: // from an earlier version of the JMX API
715
descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
716
717
break;
718
default:
719
throw new StreamCorruptedException("Got unexpected byte.");
720
}
721
}
722
}
723
724