关键类的学习
ObjectInputFilter
serialFilter字段的类型就是ObjectInputFilter,这个接口是一个函数接口(可以对方法进行赋值),其中定义的抽象方法是:
Status checkInput(FilterInfo filterInfo);
接受的参数类型FilterInfo是内部的一个接口,封装了各种过滤的信息:
interface FilterInfo {
/**
* The class of an object being deserialized.
* For arrays, it is the array type.
* For example, the array class name of a 2 dimensional array of strings is
* "{@code [[Ljava.lang.String;}".
* To check the array's element type, iteratively use
* {@link Class#getComponentType() Class.getComponentType} while the result
* is an array and then check the class.
* The {@code serialClass is null} in the case where a new object is not being
* created and to give the filter a chance to check the depth, number of
* references to existing objects, and the stream size.
*
* @return class of an object being deserialized; may be null
*/
Class<?> serialClass();
/**
* The number of array elements when deserializing an array of the class.
*
* @return the non-negative number of array elements when deserializing
* an array of the class, otherwise -1
*/
long arrayLength();
/**
* The current depth.
* The depth starts at {@code 1} and increases for each nested object and
* decrements when each nested object returns.
*
* @return the current depth
*/
long depth();
/**
* The current number of object references.
*
* @return the non-negative current number of object references
*/
long references();
/**
* The current number of bytes consumed.
* @implSpec {@code streamBytes} is implementation specific
* and may not be directly related to the object in the stream
* that caused the callback.
*
* @return the non-negative current number of bytes consumed
*/
long streamBytes();
}
这个接口作为一个函数接口,更多的情况下是作为方法引用存在的,比如在RMI中的:
RegsitryImpl::registryFilter
ObjectInputFilter.Config
static / createFilter
在Config类的静态代码块中会初始化其内部字段configuredFilter,这个字段会被赋值给serialFilter:

从代码上来看,首先会获取一个叫SERIAL_FILTER_PROPNAME的常量(其值是jdk.serialFilter),如果结果不为null的话就传入createFilter方法:
public static ObjectInputFilter createFilter(String pattern) {
Objects.requireNonNull(pattern, "pattern");
return Global.createFilter(pattern, true);
}
这里又涉及到了Global (implements) ObjectInputFilter这个类,根据官方注释,Global#createFilter方法的作用就是把字符串解析成一个ObjectInputFilter对象(Returns an ObjectInputFilter from a string of patterns),具体分析见后文的Global部分。
get(set)SerialFilter
从方法名字就可以看出来,它们是serialFilter字段的getter和setter方法。
public static ObjectInputFilter getSerialFilter() {
synchronized (serialFilterLock) {
return serialFilter;
}
}
public static void setSerialFilter(ObjectInputFilter filter) {
Objects.requireNonNull(filter, "filter");
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SerializablePermission("serialFilter"));
}
synchronized (serialFilterLock) {
if (serialFilter != null) {
throw new IllegalStateException("Serial filter can only be set once");
}
serialFilter = filter;
}
}
get(set)ObjectInputFilter
获取(初始化)一个ObjectInputStream对象中的ObjectInputFilter类型的字段(即serialFilter)。
public static ObjectInputFilter getObjectInputFilter(ObjectInputStream inputStream) {
Objects.requireNonNull(inputStream, "inputStream");
return sun.misc.SharedSecrets.getJavaOISAccess().getObjectInputFilter(inputStream);
}
public static void setObjectInputFilter(ObjectInputStream inputStream,
ObjectInputFilter filter) {
Objects.requireNonNull(inputStream, "inputStream");
sun.misc.SharedSecrets.getJavaOISAccess().setObjectInputFilter(inputStream, filter);
}
ObjectInputFilter.Config.Global
Global类是Config内部的静态类,实现了ObjectInputFilter接口,内部也有chekInput()方法的实现,所以可以把Global类的对象看作是一个过滤器,它可以直接赋值到ObjectInputStream.serialFilter字段上。
checkInput
在Global类的内部有一个储存filter的列表:
private final List<Function<Class<?>, Status>> filters;
在checkInput()方法中会遍历这个列表来检测待反序列化的类:
public Status checkInput(FilterInfo filterInfo) {
...
Class<?> clazz = filterInfo.serialClass();
if (clazz != null) {
...
if (clazz.isPrimitive()) {
// Primitive types are undecided; let someone else decide
return Status.UNDECIDED;
} else {
// Find any filter that allowed or rejected the class
final Class<?> cl = clazz;
// 关键代码,用stream来遍历filter的list
Optional<Status> status = filters.stream()
.map(f -> f.apply(cl))
.filter(p -> p != Status.UNDECIDED)
.findFirst();
return status.orElse(Status.UNDECIDED);
}
}
return Status.UNDECIDED;
}
<init>
Global的构造方法会根据传入的"String pattern"来创建不同的filter然后添加到上文中提到了存储filter的列表中(实际上列表中存储的是一个个Lambda表达式),官方称之为 ***"Pattern-Based Filters"***。
简单来说,这个String pattern就是一条一条的规则,规定着哪些类不可以被反序列化,哪些类可以被反序列化,这些规则如下(引自官方文档):
- If the pattern starts with "
!", the class is rejected if the rest of the pattern matches, otherwise it is accepted - If the pattern contains "/", the non-empty prefix up to the "/" is the module name. If the module name matches the module name of the class then the remaining pattern is matched with the class name. If there is no "/", the module name is not compared.
- If the pattern ends with "
.**" it matches any class in the package and all subpackages - If the pattern ends with "
.*" it matches any class in the package - If the pattern ends with "
*", it matches any class with the pattern as a prefix. - If the pattern is equal to the class name, it matches.
- Otherwise, the status is undecided.
createrFilter
接上文的Global#createrFilter方法,这个方法就是传入一个规则,然后初始化了一个Global对象:
static ObjectInputFilter createFilter(String pattern, boolean checkComponentType) {
Global filter = new Global(pattern, checkComponentType);
return filter.isEmpty() ? null : filter;
}
小结
小结一下每个类的主要作用:
ObjectInputFilter是filter要实现的接口,同时也是一个函数接口(意味着可以传入一个方法引用),其checkInput()方法规定着反序列化check的具体实现。Config类可以看作是一个“配置类”,规定着filter如何初始化,如何为一个ObjectInputStream设置(获取)serialFilter。Global类是JEP290规则的具体实现,它可以把一个个的String pattern转化成相应的filter;同时这个类本身也可以作为filter存在。
所以再回过头来看在Global类的静态代码块中所提到的那个常量jdk.serialFilter,这个常量其实就是一个属性名,Java会获取这个属性名(key)所对应的value,然后以这个value作为"String pattern",来创建一个filter(Global对象)。
A process-wide filter is configured via a system property or a configuration file. The system property, if supplied, supersedes the security property value.
-
*System property jdk.serialFilter
-
*Security property jdk.serialFilter in conf/security/java.properties
两种过滤模式
两种过滤模式:
- 全局过滤
- 局部过滤
全局过滤
全局过滤是指,在ObjectInputStream的创建过程中,通过ObjectInputFilter.Config这个内部类来为serialFilter赋值,进而所有ObjectInputStream对象在创建的时候就完成了serialFilter字段的初始化工作。
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
// 从Config中获取serialFilter的值
serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
// ObjectInputFilter.Config#gerSerialFilter
public static ObjectInputFilter getSerialFilter() {
synchronized (serialFilterLock) {
return serialFilter;
}
}
局部过滤
局部过滤是指,在ObjectInputStream的创建过程中不初始化serialFilter字段,而是在需要的时候对单个ObjectInputStream对象进行单独设置。
private final void setInternalObjectInputFilter(ObjectInputFilter filter) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SerializablePermission("serialFilter"));
}
// Allow replacement of the process-wide filter if not already set
if (serialFilter != null &&
serialFilter != ObjectInputFilter.Config.getSerialFilter()) {
throw new IllegalStateException("filter can not be set more than once");
}
if (totalObjectRefs > 0 && !Caches.SET_FILTER_AFTER_READ) {
throw new IllegalStateException(
"filter can not be set after an object has been read");
}
this.serialFilter = filter;
}


















