package io.openapitools.swagger; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.ws.rs.Path; import javax.ws.rs.core.Application; import org.apache.maven.plugin.logging.Log; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ConfigurationBuilder; import io.swagger.v3.oas.annotations.OpenAPIDefinition; /** * Scan for classes with {@link Path} annotation or {@link OpenAPIDefinition} * annotation, and for {@link Application} instances. */ class JaxRSScanner { private final Log log; private final Set<String> resourcePackages; private final boolean useResourcePackagesChildren; public JaxRSScanner(Log log, Set<String> resourcePackages, Boolean useResourcePackagesChildren) { this.log = log; this.resourcePackages = resourcePackages == null ? Collections.emptySet() : new HashSet<>(resourcePackages); this.useResourcePackagesChildren = useResourcePackagesChildren != null && useResourcePackagesChildren; } Application applicationInstance() { ConfigurationBuilder config = ConfigurationBuilder .build(resourcePackages) .setScanners(new ResourcesScanner(), new TypeAnnotationsScanner(), new SubTypesScanner()); Reflections reflections = new Reflections(config); Set<Class<? extends Application>> applicationClasses = reflections.getSubTypesOf(Application.class) .stream() .filter(this::filterClassByResourcePackages) .collect(Collectors.toSet()); if (applicationClasses.isEmpty()) { return null; } if (applicationClasses.size() > 1) { log.warn("More than one javax.ws.rs.core.Application classes found on the classpath, skipping"); return null; } return ClassUtils.createInstance(applicationClasses.iterator().next()); } Set<Class<?>> classes() { ConfigurationBuilder config = ConfigurationBuilder .build(resourcePackages) .setScanners(new ResourcesScanner(), new TypeAnnotationsScanner(), new SubTypesScanner()); Reflections reflections = new Reflections(config); Stream<Class<?>> apiClasses = reflections.getTypesAnnotatedWith(Path.class) .stream() .filter(this::filterClassByResourcePackages); Stream<Class<?>> defClasses = reflections.getTypesAnnotatedWith(OpenAPIDefinition.class) .stream() .filter(this::filterClassByResourcePackages); return Stream.concat(apiClasses, defClasses).collect(Collectors.toSet()); } private boolean filterClassByResourcePackages(Class<?> cls) { return resourcePackages.isEmpty() || resourcePackages.contains(cls.getPackage().getName()) || (useResourcePackagesChildren && resourcePackages.stream().anyMatch(p -> cls.getPackage().getName().startsWith(p))); } }