View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.io.serialization;
21  
22  import java.io.ObjectStreamClass;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.function.Predicate;
26  import java.util.regex.Pattern;
27  import java.util.stream.Stream;
28  
29  /**
30   * A predicate (boolean-valued function) of one argument to accept and reject classes.
31   * <p>
32   * The reject list takes precedence over the accept list.
33   * </p>
34   *
35   * @since 2.18.0
36   */
37  public class ObjectStreamClassPredicate implements Predicate<ObjectStreamClass> {
38  
39      // This is not a Set for now to avoid ClassNameMatchers requiring proper implementations of hashCode() and equals().
40      private final List<ClassNameMatcher> acceptMatchers = new ArrayList<>();
41  
42      // This is not a Set for now to avoid ClassNameMatchers requiring proper implementations of hashCode() and equals().
43      private final List<ClassNameMatcher> rejectMatchers = new ArrayList<>();
44  
45      /**
46       * Constructs a new instance.
47       */
48      public ObjectStreamClassPredicate() {
49          // empty
50      }
51  
52      /**
53       * Accepts the specified classes for deserialization, unless they are otherwise rejected.
54       * <p>
55       * The reject list takes precedence over the accept list.
56       * </p>
57       *
58       * @param classes Classes to accept
59       * @return this object
60       */
61      public ObjectStreamClassPredicate accept(final Class<?>... classes) {
62          Stream.of(classes).map(c -> new FullClassNameMatcher(c.getName())).forEach(acceptMatchers::add);
63          return this;
64      }
65  
66      /**
67       * Accepts class names where the supplied ClassNameMatcher matches for deserialization, unless they are otherwise rejected.
68       * <p>
69       * The reject list takes precedence over the accept list.
70       * </p>
71       *
72       * @param matcher a class name matcher to <em>accept</em> objects.
73       * @return this instance.
74       */
75      public ObjectStreamClassPredicate accept(final ClassNameMatcher matcher) {
76          acceptMatchers.add(matcher);
77          return this;
78      }
79  
80      /**
81       * Accepts class names that match the supplied pattern for deserialization, unless they are otherwise rejected.
82       * <p>
83       * The reject list takes precedence over the accept list.
84       * </p>
85       *
86       * @param pattern a Pattern for compiled regular expression.
87       * @return this instance.
88       */
89      public ObjectStreamClassPredicate accept(final Pattern pattern) {
90          acceptMatchers.add(new RegexpClassNameMatcher(pattern));
91          return this;
92      }
93  
94      /**
95       * Accepts the wildcard specified classes for deserialization, unless they are otherwise rejected.
96       * <p>
97       * The reject list takes precedence over the accept list.
98       * </p>
99       *
100      * @param patterns Wildcard file name patterns as defined by {@link org.apache.commons.io.FilenameUtils#wildcardMatch(String, String)
101      *                 FilenameUtils.wildcardMatch}
102      * @return this instance.
103      */
104     public ObjectStreamClassPredicate accept(final String... patterns) {
105         Stream.of(patterns).map(WildcardClassNameMatcher::new).forEach(acceptMatchers::add);
106         return this;
107     }
108 
109     /**
110      * Rejects the specified classes for deserialization, even if they are otherwise accepted.
111      * <p>
112      * The reject list takes precedence over the accept list.
113      * </p>
114      *
115      * @param classes Classes to reject
116      * @return this instance.
117      */
118     public ObjectStreamClassPredicate reject(final Class<?>... classes) {
119         Stream.of(classes).map(c -> new FullClassNameMatcher(c.getName())).forEach(rejectMatchers::add);
120         return this;
121     }
122 
123     /**
124      * Rejects class names where the supplied ClassNameMatcher matches for deserialization, even if they are otherwise accepted.
125      * <p>
126      * The reject list takes precedence over the accept list.
127      * </p>
128      *
129      * @param m the matcher to use
130      * @return this instance.
131      */
132     public ObjectStreamClassPredicate reject(final ClassNameMatcher m) {
133         rejectMatchers.add(m);
134         return this;
135     }
136 
137     /**
138      * Rejects class names that match the supplied pattern for deserialization, even if they are otherwise accepted.
139      * <p>
140      * The reject list takes precedence over the accept list.
141      * </p>
142      *
143      * @param pattern standard Java regexp
144      * @return this instance.
145      */
146     public ObjectStreamClassPredicate reject(final Pattern pattern) {
147         rejectMatchers.add(new RegexpClassNameMatcher(pattern));
148         return this;
149     }
150 
151     /**
152      * Rejects the wildcard specified classes for deserialization, even if they are otherwise accepted.
153      * <p>
154      * The reject list takes precedence over the accept list.
155      * </p>
156      *
157      * @param patterns Wildcard file name patterns as defined by {@link org.apache.commons.io.FilenameUtils#wildcardMatch(String, String)
158      *                 FilenameUtils.wildcardMatch}
159      * @return this instance.
160      */
161     public ObjectStreamClassPredicate reject(final String... patterns) {
162         Stream.of(patterns).map(WildcardClassNameMatcher::new).forEach(rejectMatchers::add);
163         return this;
164     }
165 
166     /**
167      * Tests that the ObjectStreamClass conforms to requirements.
168      * <p>
169      * The reject list takes precedence over the accept list.
170      * </p>
171      *
172      * @param objectStreamClass The ObjectStreamClass to test.
173      * @return true if the input is accepted, false if rejected, false if neither.
174      */
175     @Override
176     public boolean test(final ObjectStreamClass objectStreamClass) {
177         return test(objectStreamClass.getName());
178     }
179 
180     /**
181      * Tests that the class name conforms to requirements.
182      * <p>
183      * The reject list takes precedence over the accept list.
184      * </p>
185      *
186      * @param name The class name to test.
187      * @return true if the input is accepted, false if rejected, false if neither.
188      */
189     public boolean test(final String name) {
190         // The reject list takes precedence over the accept list.
191         for (final ClassNameMatcher m : rejectMatchers) {
192             if (m.matches(name)) {
193                 return false;
194             }
195         }
196         for (final ClassNameMatcher m : acceptMatchers) {
197             if (m.matches(name)) {
198                 return true;
199             }
200         }
201         return false;
202     }
203 
204 }