Java I/O 24 - ObjectInputStream内部类

  关于 java.io.ObjectInputStream 内部类的部分笔记,里面涉及到了HandleTable、ValidationList、GetField及其实现等几个内部类的声明和实现。本文演示代码段的执行环境基于JDK版本1.7

概述

  HandleTable是一个非同步表,用来跟踪对象映射的连接句柄,以及反序列对象过程中发生的ClassNotFoundException异常。这个类实现了一个异常传播算法来决定哪些对象应该被认为是属于异常ClassNotFoundException的。

  关于该表的使用场景,大致可分为如下几种:在反序列过程中,一个给定对象通过assign方法第一次被分配了一个句柄,此时该句柄属于“开放”状态。其中对其他句柄的异常状态的依赖关系可以通过调用markDependency方法注册,或者通过调用markException直接与句柄关联一个异常。如果当前句柄被指向了一个异常,那么根据异常传播机制和当前句柄有关联的其他对象都会被标记为异常态。一旦所有的异常信息/依赖都被注册了,那么当前句柄就可以通过close()被“关闭”了。通过finish()方法允许异常传播算法删除相关的依赖链,减少性能和内存损耗。

  ValidationList是一个优先级队列集合,用来存储在对象引用图谱被完全反序列化恢复之后需要执行的回调方法。

  GetFieldImpl实现了GetField(ObjectInputStream的静态抽象类)声明的所有方法。提供了从输入流中读取字段数据内容的方法。

HandleTable

Constructor Summary

HandleTable(int initialCapacity)

1
2
3
4
5
HandleTable(int initialCapacity) {
status = new byte[initialCapacity];
entries = new Object[initialCapacity];
deps = new HandleList[initialCapacity];
}

  初始化一个句柄表。status维护了句柄->对象状态信息,entries维护了句柄->对象/异常实体信息(该过程依赖于status),deps维护了句柄->依赖的句柄列表信息。

部分方法

int assign(Object obj)

1
2
3
4
5
6
7
8
int assign(Object obj) {
if (size >= entries.length) {
grow();
}
status[size] = STATUS_UNKNOWN;
entries[size] = obj;
return size++;
}

  分配下一个可用的句柄给入参对象obj,并返回分配的句柄信息。一旦对象彻底完成了反序列操作,句柄应该通过finish()方法置为“结束”状态。

  如果数组空间不够,就执行扩容处理。

private void grow()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void grow() {
int newCapacity = (entries.length << 1) + 1;

byte[] newStatus = new byte[newCapacity];
Object[] newEntries = new Object[newCapacity];
HandleList[] newDeps = new HandleList[newCapacity];

System.arraycopy(status, 0, newStatus, 0, size);
System.arraycopy(entries, 0, newEntries, 0, size);
System.arraycopy(deps, 0, newDeps, 0, size);

status = newStatus;
entries = newEntries;
deps = newDeps;
}

  按照当前数组容量的两倍进行扩容处理。

void markDependency(int dependent, int target)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void markDependency(int dependent, int target) {
if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
return;
}
switch (status[dependent]) {

case STATUS_UNKNOWN:
switch (status[target]) {
case STATUS_OK:
// ignore dependencies on objs with no exception
break;

case STATUS_EXCEPTION:
// eagerly propagate exception
markException(dependent,
(ClassNotFoundException) entries[target]);
break;

case STATUS_UNKNOWN:
// add to dependency list of target
if (deps[target] == null) {
deps[target] = new HandleList();
}
deps[target].add(dependent);

// remember lowest unresolved target seen
if (lowDep < 0 || lowDep > target) {
lowDep = target;
}
break;

default:
throw new InternalError();
}
break;

case STATUS_EXCEPTION:
break;

default:
throw new InternalError();
}
}

  完成句柄依赖绑定。dependent句柄必须是处于“开启”状态的句柄,如果dependent句柄或target句柄都为空,那么直接返回不做处理。

  如果dependent句柄处于“开启”状态(status = 2),那么检查target句柄。如果target的状态为OK,不做处理,如果状态为STATUS_EXCEPTION,那么需要将target句柄指向的异常传递给dependent句柄,调用的是markException(int handle, ClassNotFoundException ex)方法。如果状态为STATUS_UNKNOWN,那么就把dependent指向给target。

void markException(int handle, ClassNotFoundException ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void markException(int handle, ClassNotFoundException ex) {
switch (status[handle]) {
case STATUS_UNKNOWN:
status[handle] = STATUS_EXCEPTION;
entries[handle] = ex;

// propagate exception to dependents
HandleList dlist = deps[handle];
if (dlist != null) {
int ndeps = dlist.size();
for (int i = 0; i < ndeps; i++) {
markException(dlist.get(i), ex);
}
deps[handle] = null;
}
break;

case STATUS_EXCEPTION:
break;

default:
throw new InternalError();
}
}

  将ClassNotFoundException异常关联到当前活动句柄上。

void finish(int handle)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void finish(int handle) {
int end;
if (lowDep < 0) {
// no pending unknowns, only resolve current handle
end = handle + 1;
} else if (lowDep >= handle) {
// pending unknowns now clearable, resolve all upward handles
end = size;
lowDep = -1;
} else {
// unresolved backrefs present, can't resolve anything yet
return;
}

// change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
for (int i = handle; i < end; i++) {
switch (status[i]) {
case STATUS_UNKNOWN:
status[i] = STATUS_OK;
deps[i] = null;
break;

case STATUS_OK:
case STATUS_EXCEPTION:
break;

default:
throw new InternalError();
}
}
}

  将指定句柄标记为结束状态,标记完成后不会有新的依赖会指向到当前句柄上。

void setObject(int handle, Object obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void setObject(int handle, Object obj) {
switch (status[handle]) {
case STATUS_UNKNOWN:
case STATUS_OK:
entries[handle] = obj;
break;

case STATUS_EXCEPTION:
break;

default:
throw new InternalError();
}
}

  将handle句柄指向的对象替换为obj。

Object lookupObject(int handle)

1
2
3
4
Object lookupObject(int handle) {
return (handle != NULL_HANDLE &&
status[handle] != STATUS_EXCEPTION) ? entries[handle] : null;
}

  根据handle句柄查找对象。如果存在就从entries数组中返回对应的对象,否则返回null。

ClassNotFoundException lookupException(int handle)

1
2
3
4
5
ClassNotFoundException lookupException(int handle) {
return (handle != NULL_HANDLE &&
status[handle] == STATUS_EXCEPTION) ?
(ClassNotFoundException) entries[handle] : null;
}

  根据handle句柄查找对应的异常。如果存在就从entries数组中返回对应的异常,否则返回null。

void clear()

1
2
3
4
5
6
7
void clear() {
Arrays.fill(status, 0, size, (byte) 0);
Arrays.fill(entries, 0, size, null);
Arrays.fill(deps, 0, size, null);
lowDep = -1;
size = 0;
}

  将所有内容全部清空。

int size()

1
2
3
int size() {
return size;
}

  返回表中存储注册的句柄数量。

private static class HandleList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static class HandleList {
private int[] list = new int[4];
private int size = 0;

public HandleList() {
}

public void add(int handle) {
if (size >= list.length) {
int[] newList = new int[list.length << 1];
System.arraycopy(list, 0, newList, 0, list.length);
list = newList;
}
list[size++] = handle;
}

public int get(int index) {
if (index >= size) {
throw new ArrayIndexOutOfBoundsException();
}
return list[index];
}

public int size() {
return size;
}
}

  一个内部使用的长度可增长的句柄List集合实现。在HandleTable中用来维护句柄依赖信息。

ValidationList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
private static class ValidationList {

private static class Callback {
final ObjectInputValidation obj;
final int priority;
Callback next;
final AccessControlContext acc;

Callback(ObjectInputValidation obj, int priority, Callback next,
AccessControlContext acc)
{
this.obj = obj;
this.priority = priority;
this.next = next;
this.acc = acc;
}
}

/** linked list of callbacks */
private Callback list;

/**
* Creates new (empty) ValidationList.
*/
ValidationList() {
}

/**
* Registers callback. Throws InvalidObjectException if callback
* object is null.
*/
void register(ObjectInputValidation obj, int priority)
throws InvalidObjectException
{
if (obj == null) {
throw new InvalidObjectException("null callback");
}

Callback prev = null, cur = list;
while (cur != null && priority < cur.priority) {
prev = cur;
cur = cur.next;
}
AccessControlContext acc = AccessController.getContext();
if (prev != null) {
prev.next = new Callback(obj, priority, cur, acc);
} else {
list = new Callback(obj, priority, list, acc);
}
}

/**
* Invokes all registered callbacks and clears the callback list.
* Callbacks with higher priorities are called first; those with equal
* priorities may be called in any order. If any of the callbacks
* throws an InvalidObjectException, the callback process is terminated
* and the exception propagated upwards.
*/
void doCallbacks() throws InvalidObjectException {
try {
while (list != null) {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>()
{
public Void run() throws InvalidObjectException {
list.obj.validateObject();
return null;
}
}, list.acc);
list = list.next;
}
} catch (PrivilegedActionException ex) {
list = null;
throw (InvalidObjectException) ex.getException();
}
}

/**
* Resets the callback list to its initial (empty) state.
*/
public void clear() {
list = null;
}
}

ObjectInputStream.GetField

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static abstract class GetField {

public abstract ObjectStreamClass getObjectStreamClass();

public abstract boolean defaulted(String name) throws IOException;

public abstract boolean get(String name, boolean val) throws IOException;

public abstract byte get(String name, byte val) throws IOException;

public abstract char get(String name, char val) throws IOException;

public abstract short get(String name, short val) throws IOException;

public abstract int get(String name, int val) throws IOException;

public abstract long get(String name, long val) throws IOException;

public abstract float get(String name, float val) throws IOException;

public abstract double get(String name, double val) throws IOException;

public abstract Object get(String name, Object val) throws IOException;
}

GetFieldImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
private class GetFieldImpl extends GetField {

/** 带有被序列化了的字段内容的类描述符 */
private final ObjectStreamClass desc;
/** 基础数据类型字段 */
private final byte[] primVals;
/** 对象类型字段 */
private final Object[] objVals;
/** 字段值内容句柄 */
private final int[] objHandles;

/** 构造方法,完成初始化操作 */
GetFieldImpl(ObjectStreamClass desc) {
this.desc = desc;
primVals = new byte[desc.getPrimDataSize()];
objVals = new Object[desc.getNumObjFields()];
objHandles = new int[objVals.length];
}

public ObjectStreamClass getObjectStreamClass() {
return desc;
}

/** 如果name字段的值是默认的,那么返回true */
public boolean defaulted(String name) throws IOException {
return (getFieldOffset(name, null) < 0);
}

/** 获取name字段的boolean值,如果没有值,那么就用val替换 */
public boolean get(String name, boolean val) throws IOException {
int off = getFieldOffset(name, Boolean.TYPE);
return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
}

/** 获取name字段的byte值,如果没有值,那么就用val替换 */
public byte get(String name, byte val) throws IOException {
int off = getFieldOffset(name, Byte.TYPE);
return (off >= 0) ? primVals[off] : val;
}

/** 获取name字段的char值,如果没有值,那么就用val替换 */
public char get(String name, char val) throws IOException {
int off = getFieldOffset(name, Character.TYPE);
return (off >= 0) ? Bits.getChar(primVals, off) : val;
}

/** 获取name字段的short值,如果没有值,那么就用val替换 */
public short get(String name, short val) throws IOException {
int off = getFieldOffset(name, Short.TYPE);
return (off >= 0) ? Bits.getShort(primVals, off) : val;
}

/** 获取name字段的int值,如果没有值,那么就用val替换 */
public int get(String name, int val) throws IOException {
int off = getFieldOffset(name, Integer.TYPE);
return (off >= 0) ? Bits.getInt(primVals, off) : val;
}

/** 获取name字段的float值,如果没有值,那么就用val替换 */
public float get(String name, float val) throws IOException {
int off = getFieldOffset(name, Float.TYPE);
return (off >= 0) ? Bits.getFloat(primVals, off) : val;
}

/** 获取name字段的long值,如果没有值,那么就用val替换 */
public long get(String name, long val) throws IOException {
int off = getFieldOffset(name, Long.TYPE);
return (off >= 0) ? Bits.getLong(primVals, off) : val;
}

/** 获取name字段的double值,如果没有值,那么就用val替换 */
public double get(String name, double val) throws IOException {
int off = getFieldOffset(name, Double.TYPE);
return (off >= 0) ? Bits.getDouble(primVals, off) : val;
}

/** 获取name字段的Object值,如果没有值,那么就用val替换 */
public Object get(String name, Object val) throws IOException {
int off = getFieldOffset(name, Object.class);
if (off >= 0) {
int objHandle = objHandles[off];
handles.markDependency(passHandle, objHandle);
return (handles.lookupException(objHandle) == null) ?
objVals[off] : null;
} else {
return val;
}
}

/** 从流里读取基本数据类型和对象类型的字段值内容 */
void readFields() throws IOException {
bin.readFully(primVals, 0, primVals.length, false);

int oldHandle = passHandle;
ObjectStreamField[] fields = desc.getFields(false);
int numPrimFields = fields.length - objVals.length;
for (int i = 0; i < objVals.length; i++) {
objVals[i] = readObject0(fields[numPrimFields + i].isUnshared());
objHandles[i] = passHandle;
}
passHandle = oldHandle;
}

/** 得到指定类型和名字的字段的偏移量 */
private int getFieldOffset(String name, Class type) {
ObjectStreamField field = desc.getField(name, type);
if (field != null) {
return field.getOffset();
} else if (desc.getLocalDesc().getField(name, type) != null) {
return -1;
} else {
throw new IllegalArgumentException("no such field " + name +
" with type " + type);
}
}
}

涉及基础知识点

  1. NIL

参考文献

  1. NIL




------------- End of this article, thanks! -------------


  版权声明:本文由N.C.Lee创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处。
  本文作者为 N.C.Lee
  本文标题为 Java I/O 24 - ObjectInputStream内部类
  本文链接为 https://marcuseddie.github.io/2018/java-ObjectInputStream-InternalClass.html