private static void searchResource(@Nonnull Results results,
	                                   @Nonnull ExecutorService service,
	                                   @Nonnull SearchFeedback feedback,
	                                   @Nonnull WorkspaceResource resource,
	                                   @Nonnull WorkspacePathNode workspacePath,
	                                   @Nullable AndroidClassSearchVisitor androidClassVisitor,
	                                   @Nullable JvmClassSearchVisitor jvmClassVisitor,
	                                   @Nullable FileSearchVisitor fileVisitor) {
		// Recursively search embedded resources.
		for (WorkspaceFileResource embeddedResource : resource.getEmbeddedResources().values()) {
			searchResource(results, service, feedback, embeddedResource, workspacePath,
					androidClassVisitor, jvmClassVisitor, fileVisitor);
		}

		// Visit android content
		ResourcePathNode resourcePath = workspacePath.child(resource);
		if (androidClassVisitor != null) {
			for (AndroidClassBundle bundle : resource.getAndroidClassBundles().values()) {
				BundlePathNode bundlePath = resourcePath.child(bundle);
				for (AndroidClassInfo classInfo : bundle) {
					if (feedback.hasRequestedCancellation())
						break;
					if (!feedback.doVisitClass(classInfo))
						continue;
					ClassPathNode classPath = bundlePath
							.child(classInfo.getPackageName())
							.child(classInfo);
					service.submit(() -> {
						if (feedback.hasRequestedCancellation())
							return;
						androidClassVisitor.visit(getResultSink(results, feedback), classPath, classInfo);
					});
				}
			}
		}

		// Visit JVM content
		if (jvmClassVisitor != null) {
			Stream.concat(resource.jvmClassBundleStream(), resource.versionedJvmClassBundleStream()).forEach(bundle -> {
				BundlePathNode bundlePath = resourcePath.child(bundle);
				for (JvmClassInfo classInfo : bundle) {
					if (feedback.hasRequestedCancellation())
						break;
					if (!feedback.doVisitClass(classInfo))
						continue;
					ClassPathNode classPath = bundlePath
							.child(classInfo.getPackageName())
							.child(classInfo);
					service.submit(() -> {
						if (feedback.hasRequestedCancellation())
							return;
						jvmClassVisitor.visit(getResultSink(results, feedback), classPath, classInfo);
					});
				}
			});
		}

		// Visit file content
		if (fileVisitor != null) {
			FileBundle fileBundle = resource.getFileBundle();
			BundlePathNode bundlePath = resourcePath.child(fileBundle);
			for (FileInfo fileInfo : fileBundle) {
				if (feedback.hasRequestedCancellation())
					break;
				if (!feedback.doVisitFile(fileInfo))
					continue;
				FilePathNode filePath = bundlePath
						.child(fileInfo.getDirectoryName())
						.child(fileInfo);
				service.submit(() -> {
					if (feedback.hasRequestedCancellation())
						return;
					fileVisitor.visit(getResultSink(results, feedback), filePath, fileInfo);
				});
			}
		}
	}
@param results
		Result container to dump into.
@param service
		Thread scheduler service.
@param feedback
		Search feedback mechanism <i>(To allow user cancellation and such)</i>
@param resource
		Resource to search within.
@param workspacePath
		Root workspace path node.
@param androidClassVisitor
		Android class search visitor.
		Can be {@code null} to skip searching respective content.
@param jvmClassVisitor
		JVM class search visitor.
		Can be {@code null} to skip searching respective content.
@param fileVisitor
		File search visitor.
		Can be {@code null} to skip searching respective content.
recaf-core/src/main/java/software/coley/recaf/services/search/SearchService.java