setSerialFilterFactoryを使用したフィルタ・ファクトリの設定

メソッドObjectInputFilter.Config.setSerialFilterFactoryを呼び出してフィルタ・ファクトリを設定すると、ObjectInputStreamが構築されたとき、およびストリーム固有のフィルタがObjectInputStreamに設定されたときに、フィルタ・ファクトリのメソッドBinaryOperator<ObjectInputFilter>.apply(ObjectInputFilter t, ObjectInputFilter u)が呼び出されます。パラメータtは現在のフィルタで、uはリクエストされたフィルタです。applyが最初に呼び出されたとき、tはnullになります。JVM全体のフィルタが設定されている場合、applyが最初に呼び出されたとき、uはJVM全体のフィルタになります。それ以外の場合、uはnullになります。applyメソッド(自分で実装する必要がある)は、ストリームに使用されるフィルタを返します。applyが再度呼び出された場合、パラメータtはこの返されたフィルタになります。メソッドObjectInputStream.setObjectInputFilter(ObjectInputFilter)を使用してフィルタを設定すると、パラメータuがこのフィルタになります。

次の例では、applyメソッドが呼び出されるたびにObjectInputFilterパラメータを出力する単純なフィルタ・ファクトリを実装し、これらのパラメータを1つの結合フィルタにマージしてから、このマージ済フィルタを返します。

public class SimpleFilterFactory {

    static class MySimpleFilterFactory implements BinaryOperator<ObjectInputFilter> {
        public ObjectInputFilter apply(
            ObjectInputFilter curr, ObjectInputFilter next) {
            System.out.println("Current filter: " + curr);
            System.out.println("Requested filter: " + next);
            return ObjectInputFilter.merge(next, curr);
        }
    }            
   
    private static byte[] createSimpleStream(Object obj) {
        ByteArrayOutputStream boas = new ByteArrayOutputStream();
        try (ObjectOutputStream ois = new ObjectOutputStream(boas)) {
            ois.writeObject(obj);
            return boas.toByteArray();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        throw new RuntimeException();        
    }
            
    public static void main(String[] args) throws IOException {
        
        // Set a filter factory
        
        MySimpleFilterFactory contextFilterFactory = new MySimpleFilterFactory();
        ObjectInputFilter.Config.setSerialFilterFactory(contextFilterFactory);          
        
        // Set a stream-specific filter
        
        ObjectInputFilter filter1 =
            ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*");
        ObjectInputFilter.Config.setSerialFilter(filter1);

        // Create another filter        
        
        ObjectInputFilter intFilter = ObjectInputFilter.allowFilter(
          cl -> cl.equals(Integer.class), ObjectInputFilter.Status.UNDECIDED);        
          
        // Create input stream
          
        byte[] intByteStream = createSimpleStream(42);
        InputStream is = new ByteArrayInputStream(intByteStream);
        ObjectInputStream ois = new ObjectInputStream(is);
        ois.setObjectInputFilter(intFilter);
        
        try {
            Object obj = ois.readObject();
            System.out.println("Read obj: " + obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

この例では、次のような出力が表示されます(わかりやすくするために改行が追加されています):

Current filter: null
Requested filter: example.*;java.base/*;!*
Current filter: example.*;java.base/*;!*
Requested filter:
    merge(
        predicate(
            SimpleFilterFactory$$Lambda$8/0x0000000800c00c60@76ed5528,
            ifTrue: ALLOWED, ifFalse: UNDECIDED),
        predicate(
            SimpleFilterFactory$$Lambda$9/0x0000000800c01800@2c7b84de,
            ifTrue: REJECTED, ifFalse: UNDECIDED))
Read obj: 42

applyメソッドは2回呼び出されます。ObjectInputStream oisが作成されたとき、およびメソッドsetObjectInputFilterが呼び出されたときです。

ノート:

  • フィルタをObjectInputStreamに設定できるのは1回のみです。それ以外の場合は、IllegalStateExceptionがスローされます。
  • 予期しないデシリアライズから保護するには、セキュリティ・エキスパートは、フィルタ・ファクトリがフィルタを選択して組み合せる方法を徹底的に確認します。