@Nonnull
		@Override
		public byte[] filter(@Nonnull Workspace workspace, @Nonnull JvmClassInfo initialClassInfo, @Nonnull byte[] bytecode) {
			// Apply filters to the input bytecode first
			for (JvmBytecodeFilter filter : bytecodeFilters)
				bytecode = filter.filter(workspace, initialClassInfo, bytecode);

			// Setup filtering based on config
			byte[] filteredBytecode = bytecode;
			LazyValueHolder<ClassReader> reader = LazyValueHolder.forSupplier(() -> new ClassReader(filteredBytecode));
			LazyValueHolder<ClassWriter> cw = LazyValueHolder.forSupplier(() -> {
				// In most cases we want to pass the class-reader along to the class-writer.
				// This will allow some operations to be sped up internally by ASM.
				//
				// However, we can't do this is we're filtering debug information since it blanket copies all
				// debug attribute information without checking what the class-reader flags are.
				// Thus, when we're pruning debug info, we should pass 'null'.
				ClassReader backing = config.getFilterDebug().getValue() ? null : reader.get();
				return new ClassWriter(backing, 0);
			});
			ClassVisitor cv = null;

			// The things you want to 'filter' first need to appear last in this chain since we're building a chain
			// of visitors which delegate from one onto another.
			if (config.getFilterNonAsciiNames().getValue()) {
				cv = cw.get();
				cv = BogusNameRemovingVisitor.create(workspace, cv);
			}
			if (config.getFilterLongAnnotations().getValue()) {
				if (cv == null) cv = cw.get();
				cv = new LongAnnotationRemovingVisitor(cv, config.getFilterLongAnnotationsLength().getValue());
			}
			if (config.getFilterDuplicateAnnotations().getValue()) {
				if (cv == null) cv = cw.get();
				cv = new DuplicateAnnotationRemovingVisitor(cv);
			}
			if (config.getFilterIllegalAnnotations().getValue()) {
				if (cv == null) cv = cw.get();
				cv = new IllegalAnnotationRemovingVisitor(cv);
			}
			if (config.getFilterHollow().getValue()) {
				if (cv == null) cv = cw.get();
				cv = new ClassHollowingVisitor(cv, EnumSet.allOf(ClassHollowingVisitor.Item.class));
			}
			if (config.getFilterSignatures().getValue()) {
				if (cv == null) cv = cw.get();
				cv = new IllegalSignatureRemovingVisitor(cv);
			}
			if (config.getFilterDebug().getValue() && cv == null)
				cv = cw.get();

			// If no filtering has been requested, we never need to initialize the reader or writer.
			// Just return the original bytecode passed in.
			if (cv == null)
				return bytecode;

			try {
				int readFlags = config.getFilterDebug().getValue() ? ClassReader.SKIP_DEBUG : 0;
				reader.get().accept(cv, readFlags);
				return cw.get().toByteArray();
			} catch (Throwable t) {
				logger.error("Error applying filters to class '{}'", initialClassInfo.getName(), t);
				return bytecode;
			}
		}
JVM bytecode filter that applies multiple other filters:
<ol>
    <li>Any values in {@link #bytecodeFilters}</li>
    <li>Any filters based on the current values in {@link #config}</li>
</ol>
recaf-core/src/main/java/software/coley/recaf/services/decompile/DecompilerManager.java