Setting a Filter Factory with setSerialFilterFactory

When you set a filter factory by calling the method ObjectInputFilter.Config.setSerialFilterFactory, the filter factory's method BinaryOperator<ObjectInputFilter>.apply(ObjectInputFilter t, ObjectInputFilter u) will be invoked when an ObjectInputStream is constructed and when a stream-specific filter is set on an ObjectInputStream. The parameter t is the current filter and u is the requested filter. When apply is first invoked, t will be null. If a JVM-wide filter has been set, then when apply is first invoked, u will be the JVM-wide filter. Otherwise, u will be null. The apply method (which you must implement yourself) returns the filter to be used for the stream. If apply is invoked again, then the parameter t will be this returned filter. When you set a filter with the method ObjectInputStream.setObjectInputFilter(ObjectInputFilter), then parameter u will be this filter.

The following example implements a simple filter factory that prints its ObjectInputFilter parameters every time its apply method is invoked, merges these parameters into one combined filter, then returns this merged filter.

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();
        }
    }
}

This example prints output similar to the following (line breaks have been added for clarity):

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

The apply method is invoked twice: when the ObjectInputStream ois is created and when the method setObjectInputFilter is called.

Note:

  • You can set a filter on an ObjectInputStream only once. An IllegalStateException will be thrown otherwise.
  • To protect against unexpected deserializations, ensure that security experts thoroughly review how your filter factories select and combine filters.