1 /* 2 * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.lang.model.util; 27 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Set; 31 import java.util.EnumSet; 32 import java.util.ArrayList; 33 import java.util.LinkedHashSet; 34 35 import javax.lang.model.element.*; 36 import javax.lang.model.element.ModuleElement.Directive; 37 import javax.lang.model.element.ModuleElement.DirectiveKind; 38 import javax.lang.model.element.ModuleElement.ExportsDirective; 39 import javax.lang.model.element.ModuleElement.OpensDirective; 40 import javax.lang.model.element.ModuleElement.ProvidesDirective; 41 import javax.lang.model.element.ModuleElement.RequiresDirective; 42 import javax.lang.model.element.ModuleElement.UsesDirective; 43 44 45 /** 46 * Filters for selecting just the elements of interest from a 47 * collection of elements. The returned sets and lists are new 48 * collections and do use the argument as a backing store. The 49 * methods in this class do not make any attempts to guard against 50 * concurrent modifications of the arguments. The returned sets and 51 * lists are mutable but unsafe for concurrent access. A returned set 52 * has the same iteration order as the argument set to a method. 53 * 54 * <p>If iterables and sets containing {@code null} are passed as 55 * arguments to methods in this class, a {@code NullPointerException} 56 * will be thrown. 57 * 58 * @author Joseph D. Darcy 59 * @author Scott Seligman 60 * @author Peter von der Ahé 61 * @author Martin Buchholz 62 * @since 1.6 63 */ 64 public class ElementFilter { 65 private ElementFilter() {} // Do not instantiate. 66 67 private static final Set<ElementKind> CONSTRUCTOR_KIND = 68 Collections.unmodifiableSet(EnumSet.of(ElementKind.CONSTRUCTOR)); 69 70 private static final Set<ElementKind> FIELD_KINDS = 71 Collections.unmodifiableSet(EnumSet.of(ElementKind.FIELD, 72 ElementKind.ENUM_CONSTANT)); 73 private static final Set<ElementKind> METHOD_KIND = 74 Collections.unmodifiableSet(EnumSet.of(ElementKind.METHOD)); 75 76 private static final Set<ElementKind> PACKAGE_KIND = 77 Collections.unmodifiableSet(EnumSet.of(ElementKind.PACKAGE)); 78 79 private static final Set<ElementKind> MODULE_KIND = 80 Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE)); 81 82 @SuppressWarnings("preview") 83 private static final Set<ElementKind> TYPE_KINDS = 84 Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, 85 ElementKind.ENUM, 86 ElementKind.INTERFACE, 87 ElementKind.RECORD, 88 ElementKind.ANNOTATION_TYPE)); 89 90 @SuppressWarnings("preview") 91 private static final Set<ElementKind> RECORD_COMPONENT_KIND = 92 Set.of(ElementKind.RECORD_COMPONENT); 93 94 /** 95 * Returns a list of fields in {@code elements}. 96 * @return a list of fields in {@code elements} 97 * @param elements the elements to filter 98 */ 99 public static List<VariableElement> 100 fieldsIn(Iterable<? extends Element> elements) { 101 return listFilter(elements, FIELD_KINDS, VariableElement.class); 102 } 103 104 /** 105 * Returns a set of fields in {@code elements}. 106 * @return a set of fields in {@code elements} 107 * @param elements the elements to filter 108 */ 109 public static Set<VariableElement> 110 fieldsIn(Set<? extends Element> elements) { 111 return setFilter(elements, FIELD_KINDS, VariableElement.class); 112 } 113 114 /** 115 * {@preview Associated with records, a preview feature of the Java language. 116 * 117 * This method is associated with <i>records</i>, a preview 118 * feature of the Java language. Programs can only use this 119 * method when preview features are enabled. Preview features 120 * may be removed in a future release, or upgraded to permanent 121 * features of the Java language.} 122 * 123 * Returns a list of record components in {@code elements}. 124 * @return a list of record components in {@code elements} 125 * @param elements the elements to filter 126 * @since 14 127 */ 128 @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, 129 essentialAPI=false) 130 @SuppressWarnings("preview") 131 public static List<RecordComponentElement> 132 recordComponentsIn(Iterable<? extends Element> elements) { 133 return listFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class); 134 } 135 136 /** 137 * {@preview Associated with records, a preview feature of the Java language. 138 * 139 * This method is associated with <i>records</i>, a preview 140 * feature of the Java language. Programs can only use this 141 * method when preview features are enabled. Preview features 142 * may be removed in a future release, or upgraded to permanent 143 * features of the Java language.} 144 * 145 * Returns a set of record components in {@code elements}. 146 * @return a set of record components in {@code elements} 147 * @param elements the elements to filter 148 * @since 14 149 */ 150 @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, 151 essentialAPI=false) 152 @SuppressWarnings("preview") 153 public static Set<RecordComponentElement> 154 recordComponentsIn(Set<? extends Element> elements) { 155 return setFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class); 156 } 157 158 /** 159 * Returns a list of constructors in {@code elements}. 160 * @return a list of constructors in {@code elements} 161 * @param elements the elements to filter 162 */ 163 public static List<ExecutableElement> 164 constructorsIn(Iterable<? extends Element> elements) { 165 return listFilter(elements, CONSTRUCTOR_KIND, ExecutableElement.class); 166 } 167 168 /** 169 * Returns a set of constructors in {@code elements}. 170 * @return a set of constructors in {@code elements} 171 * @param elements the elements to filter 172 */ 173 public static Set<ExecutableElement> 174 constructorsIn(Set<? extends Element> elements) { 175 return setFilter(elements, CONSTRUCTOR_KIND, ExecutableElement.class); 176 } 177 178 /** 179 * Returns a list of methods in {@code elements}. 180 * @return a list of methods in {@code elements} 181 * @param elements the elements to filter 182 */ 183 public static List<ExecutableElement> 184 methodsIn(Iterable<? extends Element> elements) { 185 return listFilter(elements, METHOD_KIND, ExecutableElement.class); 186 } 187 188 /** 189 * Returns a set of methods in {@code elements}. 190 * @return a set of methods in {@code elements} 191 * @param elements the elements to filter 192 */ 193 public static Set<ExecutableElement> 194 methodsIn(Set<? extends Element> elements) { 195 return setFilter(elements, METHOD_KIND, ExecutableElement.class); 196 } 197 198 /** 199 * Returns a list of types in {@code elements}. 200 * @return a list of types in {@code elements} 201 * @param elements the elements to filter 202 */ 203 public static List<TypeElement> 204 typesIn(Iterable<? extends Element> elements) { 205 return listFilter(elements, TYPE_KINDS, TypeElement.class); 206 } 207 208 /** 209 * Returns a set of types in {@code elements}. 210 * @return a set of types in {@code elements} 211 * @param elements the elements to filter 212 */ 213 public static Set<TypeElement> 214 typesIn(Set<? extends Element> elements) { 215 return setFilter(elements, TYPE_KINDS, TypeElement.class); 216 } 217 218 /** 219 * Returns a list of packages in {@code elements}. 220 * @return a list of packages in {@code elements} 221 * @param elements the elements to filter 222 */ 223 public static List<PackageElement> 224 packagesIn(Iterable<? extends Element> elements) { 225 return listFilter(elements, PACKAGE_KIND, PackageElement.class); 226 } 227 228 /** 229 * Returns a set of packages in {@code elements}. 230 * @return a set of packages in {@code elements} 231 * @param elements the elements to filter 232 */ 233 public static Set<PackageElement> 234 packagesIn(Set<? extends Element> elements) { 235 return setFilter(elements, PACKAGE_KIND, PackageElement.class); 236 } 237 238 /** 239 * Returns a list of modules in {@code elements}. 240 * @return a list of modules in {@code elements} 241 * @param elements the elements to filter 242 * @since 9 243 * @spec JPMS 244 */ 245 public static List<ModuleElement> 246 modulesIn(Iterable<? extends Element> elements) { 247 return listFilter(elements, MODULE_KIND, ModuleElement.class); 248 } 249 250 /** 251 * Returns a set of modules in {@code elements}. 252 * @return a set of modules in {@code elements} 253 * @param elements the elements to filter 254 * @since 9 255 * @spec JPMS 256 */ 257 public static Set<ModuleElement> 258 modulesIn(Set<? extends Element> elements) { 259 return setFilter(elements, MODULE_KIND, ModuleElement.class); 260 } 261 262 // Assumes targetKinds and E are sensible. 263 private static <E extends Element> List<E> listFilter(Iterable<? extends Element> elements, 264 Set<ElementKind> targetKinds, 265 Class<E> clazz) { 266 List<E> list = new ArrayList<>(); 267 for (Element e : elements) { 268 if (targetKinds.contains(e.getKind())) 269 list.add(clazz.cast(e)); 270 } 271 return list; 272 } 273 274 // Assumes targetKinds and E are sensible. 275 private static <E extends Element> Set<E> setFilter(Set<? extends Element> elements, 276 Set<ElementKind> targetKinds, 277 Class<E> clazz) { 278 // Return set preserving iteration order of input set. 279 Set<E> set = new LinkedHashSet<>(); 280 for (Element e : elements) { 281 if (targetKinds.contains(e.getKind())) 282 set.add(clazz.cast(e)); 283 } 284 return set; 285 } 286 287 /** 288 * Returns a list of {@code exports} directives in {@code directives}. 289 * @return a list of {@code exports} directives in {@code directives} 290 * @param directives the directives to filter 291 * @since 9 292 * @spec JPMS 293 */ 294 public static List<ExportsDirective> 295 exportsIn(Iterable<? extends Directive> directives) { 296 return listFilter(directives, DirectiveKind.EXPORTS, ExportsDirective.class); 297 } 298 299 /** 300 * Returns a list of {@code opens} directives in {@code directives}. 301 * @return a list of {@code opens} directives in {@code directives} 302 * @param directives the directives to filter 303 * @since 9 304 */ 305 public static List<OpensDirective> 306 opensIn(Iterable<? extends Directive> directives) { 307 return listFilter(directives, DirectiveKind.OPENS, OpensDirective.class); 308 } 309 310 /** 311 * Returns a list of {@code provides} directives in {@code directives}. 312 * @return a list of {@code provides} directives in {@code directives} 313 * @param directives the directives to filter 314 * @since 9 315 * @spec JPMS 316 */ 317 public static List<ProvidesDirective> 318 providesIn(Iterable<? extends Directive> directives) { 319 return listFilter(directives, DirectiveKind.PROVIDES, ProvidesDirective.class); 320 } 321 322 /** 323 * Returns a list of {@code requires} directives in {@code directives}. 324 * @return a list of {@code requires} directives in {@code directives} 325 * @param directives the directives to filter 326 * @since 9 327 * @spec JPMS 328 */ 329 public static List<RequiresDirective> 330 requiresIn(Iterable<? extends Directive> directives) { 331 return listFilter(directives, DirectiveKind.REQUIRES, RequiresDirective.class); 332 } 333 334 /** 335 * Returns a list of {@code uses} directives in {@code directives}. 336 * @return a list of {@code uses} directives in {@code directives} 337 * @param directives the directives to filter 338 * @since 9 339 * @spec JPMS 340 */ 341 public static List<UsesDirective> 342 usesIn(Iterable<? extends Directive> directives) { 343 return listFilter(directives, DirectiveKind.USES, UsesDirective.class); 344 } 345 346 // Assumes directiveKind and D are sensible. 347 private static <D extends Directive> List<D> listFilter(Iterable<? extends Directive> directives, 348 DirectiveKind directiveKind, 349 Class<D> clazz) { 350 List<D> list = new ArrayList<>(); 351 for (Directive d : directives) { 352 if (d.getKind() == directiveKind) 353 list.add(clazz.cast(d)); 354 } 355 return list; 356 } 357 }