### Bootstrap Recaf Application Instance Source: https://context7.com/col-e/recaf/llms.txt Use Bootstrap.get() to obtain the singleton Recaf application instance. An optional consumer can customize Weld before initialization. Services like WorkspaceManager and DecompilerManager can be retrieved via the instance. ```java import software.coley.recaf.Bootstrap; import software.coley.recaf.Recaf; import software.coley.recaf.services.workspace.WorkspaceManager; import software.coley.recaf.services.decompile.DecompilerManager; // Optional: customise Weld before it is initialized (must be called before Bootstrap.get()) Bootstrap.setWeldConsumer(weld -> { // e.g. weld.addPackage(true, MyPlugin.class); }); // Obtain the single application instance Recaf recaf = Bootstrap.get(); // Retrieve any CDI-managed service WorkspaceManager workspaceManager = recaf.get(WorkspaceManager.class); DecompilerManager decompilerManager = recaf.get(DecompilerManager.class); System.out.println("Recaf ready. Current workspace: " + workspaceManager.hasCurrentWorkspace()); // Output: Recaf ready. Current workspace: false ``` -------------------------------- ### Compile and Run Java Scripts with ScriptEngine Source: https://context7.com/col-e/recaf/llms.txt Use ScriptEngine to compile and execute Java source code programmatically. This allows for dynamic script execution with access to Recaf's CDI context. The compile-then-run approach provides a cancellation handle. ```java import software.coley.recaf.services.script.ScriptEngine; import software.coley.recaf.services.script.ScriptResult; import software.coley.recaf.services.script.GenerateResult; ScriptEngine engine = recaf.get(ScriptEngine.class); String scriptSource = """ import software.coley.recaf.services.workspace.WorkspaceManager; import jakarta.inject.Inject; @Inject WorkspaceManager workspaceManager; public void run() { if (workspaceManager.hasCurrentWorkspace()) { workspaceManager.getCurrent().jvmClassesStream(false) .forEach(p -> System.out.println("Class: " + p.getValue().getName())); } else { System.out.println("No workspace open"); } } """; // Compile first, then run (enables cancellation handle) engine.compile(scriptSource) .thenCompose(generateResult -> { if (!generateResult.hasErrors()) { return engine.run(generateResult); } else { generateResult.getErrors().forEach(e -> System.err.println("Compile error: " + e)); return CompletableFuture.completedFuture(null); } }) .thenAccept(result -> { if (result != null && result.getException() != null) result.getException().printStackTrace(); else System.out.println("Script completed successfully"); }); // Or run directly without a compile step engine.run(scriptSource) .join(); // block for demo purposes ``` -------------------------------- ### Search Workspace with String and Reference Queries Source: https://context7.com/col-e/recaf/llms.txt Use SearchService to find strings containing specific text or references to classes. Requires importing necessary search and result classes. ```java import software.coley.recaf.services.search.SearchService; import software.coley.recaf.services.search.query.*; import software.coley.recaf.services.search.match.StringPredicateProvider; import software.coley.recaf.services.search.result.*; SearchService search = recaf.get(SearchService.class); Workspace workspace = wm.getCurrent(); // Search for any string containing "password" StringPredicateProvider spp = recaf.get(StringPredicateProvider.class); Results strResults = search.search(workspace, new StringQuery(spp.newContainsPredicate("password"))); strResults.ofType(StringResult.class).forEach(r -> System.out.println("String match at: " + r.getPath() + " => " + r.getValue())); // Search for references to a specific class Results refResults = search.search(workspace, new ReferenceQuery(null, "java/io/FileInputStream", null, null)); refResults.ofType(ClassReferenceResult.class).forEach(r -> System.out.println("Class ref at: " + r.getPath())); ``` ```java // Combined multi-query (runs all queries in one pass) NumberPredicateProvider npp = recaf.get(NumberPredicateProvider.class); Results combined = search.search(workspace, List.of( new StringQuery(spp.newEqualsPredicate("DEBUG")), new NumberQuery(npp.newEqualsPredicate(42)) ))); System.out.println("Combined results: " + combined.size()); ``` ```java // Cancellable search with feedback CancellableSearchFeedback feedback = new CancellableSearchFeedback(); Results partial = search.search(workspace, new StringQuery(spp.newContainsPredicate("secret")), feedback); // Call feedback.requestCancellation() from another thread to stop early ``` -------------------------------- ### Apply Mappings to Workspace Resources Source: https://context7.com/col-e/recaf/llms.txt Parse Proguard mappings and apply them to the current workspace's primary resource or specific classes. The results can be committed to update bundles. ```java import software.coley.recaf.services.mapping.MappingApplierService; import software.coley.recaf.services.mapping.MappingApplier; import software.coley.recaf.services.mapping.IntermediateMappings; import software.coley.recaf.services.mapping.MappingResults; import software.coley.recaf.services.mapping.format.MappingFormatManager; import software.coley.recaf.services.mapping.format.ProguardMappings; MappingApplierService mas = recaf.get(MappingApplierService.class); MappingFormatManager formatManager = recaf.get(MappingFormatManager.class); // Parse a Proguard mapping file String proguardText = """ com.example.a -> com.example.Foo: int x -> count void b() -> run """; ProguardMappings fmt = (ProguardMappings) formatManager.getFormat("Proguard"); IntermediateMappings mappings = fmt.read(proguardText); // Apply to the current workspace's primary resource MappingApplier applier = mas.inCurrentWorkspace(); if (applier != null) { MappingResults results = applier.applyToPrimaryResource(mappings); // Commit: updates bundles with renamed/remapped classes results.apply(); System.out.println("Renamed " + results.size() + " classes"); // Output: Renamed 1 classes } // Apply to a specific resource targeting only selected classes WorkspaceResource primary = workspace.getPrimaryResource(); JvmClassBundle bundle = primary.getJvmClassBundle(); Collection targets = List.of(bundle.get("com/example/a")); MappingResults selective = applier.applyToClasses(mappings, primary, bundle, targets); selective.apply(); ``` -------------------------------- ### Navigate Class Hierarchies with InheritanceGraph Source: https://context7.com/col-e/recaf/llms.txt Obtain an InheritanceGraph instance to analyze class relationships. Query for parents, children, common supertypes, and assignability. ```java import software.coley.recaf.services.inheritance.InheritanceGraphService; import software.coley.recaf.services.inheritance.InheritanceGraph; import software.coley.recaf.services.inheritance.InheritanceVertex; InheritanceGraphService igs = recaf.get(InheritanceGraphService.class); InheritanceGraph graph = igs.newInheritanceGraph(workspace); // Or use the cached one for the current workspace: // InheritanceGraph graph = igs.getCurrentWorkspaceInheritanceGraph(); InheritanceVertex vertex = graph.getVertex("com/example/Foo"); if (vertex != null) { // Direct parents vertex.getParents().forEach(p -> System.out.println("Parent: " + p.getName())); // All children (recursive) vertex.getAllChildren().forEach(c -> System.out.println("Child: " + c.getName())); // Common supertype between two classes Set common = graph.getCommonSuperClasses("com/example/Foo", "com/example/Bar"); System.out.println("Common supers: " + common); // Check if a class is assignable System.out.println("Is Runnable? " + vertex.hasParent("java/lang/Runnable", true)); } ``` -------------------------------- ### WorkspaceManager: Open and Close Workspaces Source: https://context7.com/col-e/recaf/llms.txt The WorkspaceManager service tracks the active workspace and fires open/close events. Workspaces can be created from resources, activated, and closed. Listeners can be added to react to these events. ```java import software.coley.recaf.services.workspace.WorkspaceManager; import software.coley.recaf.workspace.model.Workspace; import software.coley.recaf.workspace.model.resource.WorkspaceFileResource; import software.coley.recaf.workspace.model.resource.WorkspaceFileResourceBuilder; import software.coley.recaf.workspace.model.bundle.BasicJvmClassBundle; import software.coley.recaf.workspace.model.bundle.BasicFileBundle; WorkspaceManager wm = recaf.get(WorkspaceManager.class); // Listen for workspace open/close events wm.addWorkspaceOpenListener(workspace -> System.out.println("Opened: " + workspace)); wm.addWorkspaceCloseListener(workspace -> System.out.println("Closed: " + workspace)); // Build a workspace resource from existing class/file bundles BasicJvmClassBundle classBundle = new BasicJvmClassBundle(); BasicFileBundle fileBundle = new BasicFileBundle(); WorkspaceFileResource resource = new WorkspaceFileResourceBuilder() .withJvmClassBundle(classBundle) .withFileBundle(fileBundle) .build(); // Create and activate a new workspace Workspace workspace = wm.createWorkspace(resource); boolean opened = wm.setCurrent(workspace); System.out.println("Workspace set: " + opened); // Output: Workspace set: true // Access current workspace Workspace current = wm.getCurrent(); System.out.println("Has workspace: " + wm.hasCurrentWorkspace()); // Output: Has workspace: true // Close it wm.closeCurrent(); ``` -------------------------------- ### Attach to Live JVM Processes Source: https://context7.com/col-e/recaf/llms.txt Use AttachManager to discover, connect to, and manage remote JVM processes. The attached JVM's classes are exposed as a workspace resource. ```java import software.coley.recaf.services.attach.AttachManager; import com.sun.tools.attach.VirtualMachineDescriptor; import software.coley.recaf.workspace.model.resource.WorkspaceRemoteVmResource; AttachManager am = recaf.get(AttachManager.class); if (!am.canAttach()) { System.out.println("Attach not supported on this platform"); return; } // Scan for running JVMs am.scan(); // List discovered JVMs for (VirtualMachineDescriptor desc : am.getVirtualMachineDescriptors()) { int pid = am.getVirtualMachinePid(desc); String main = am.getVirtualMachineMainClass(desc); System.out.printf("PID %d: %s%n", pid, main); } // Attach to a target JVM (e.g. the first one found) VirtualMachineDescriptor target = am.getVirtualMachineDescriptors().get(0); WorkspaceRemoteVmResource remote = am.createRemoteResource(target); remote.connect(); // triggers agent injection // Use the remote resource as a workspace resource Workspace liveWorkspace = wm.createWorkspace(remote); wm.setCurrent(liveWorkspace); System.out.println("Live classes loaded: " + remote.getJvmClassBundle().size()); ``` -------------------------------- ### Querying Classes and Files in Workspace Source: https://context7.com/col-e/recaf/llms.txt Use the Workspace API to find specific classes or files by name, or to filter classes based on criteria like annotations. It also supports streaming all JVM classes and accessing non-class file entries. ```java import software.coley.recaf.workspace.model.Workspace; import software.coley.recaf.path.ClassPathNode; import software.coley.recaf.path.FilePathNode; import software.coley.recaf.info.JvmClassInfo; Workspace workspace = wm.getCurrent(); // Find a single class by internal name ClassPathNode path = workspace.findClass("com/example/MyClass"); if (path != null) { JvmClassInfo cls = (JvmClassInfo) path.getValue(); System.out.println("Found class: " + cls.getName() + " (v" + cls.getVersion() + ")"); } // Find classes matching a predicate var results = workspace.findJvmClasses(c -> c.hasAnnotation("Ljava/lang/Deprecated;")); System.out.println("Deprecated classes: " + results.size()); // Stream all JVM classes (including internal JRE support resource) workspace.jvmClassesStream(true) .map(n -> (JvmClassInfo) n.getValue()) .filter(c -> c.getName().startsWith("com/example")) .forEach(c -> System.out.println(" - " + c.getName())); // Find a file (non-class entry) by name FilePathNode filePath = workspace.findFile("META-INF/MANIFEST.MF"); if (filePath != null) System.out.println("Manifest found in: " + filePath.getResource()); // Find a package var packagePath = workspace.findPackage("com/example/util"); System.out.println("Package path: " + packagePath); ``` -------------------------------- ### Analyze Method Calls with CallGraphService Source: https://context7.com/col-e/recaf/llms.txt Utilize CallGraphService to build and query a call graph of the current workspace. This service helps in understanding method relationships, enabling impact analysis for refactoring tasks. ```java import software.coley.recaf.services.callgraph.CallGraphService; import software.coley.recaf.services.callgraph.CallGraph; import software.coley.recaf.services.callgraph.MethodVertex; CallGraphService cgs = recaf.get(CallGraphService.class); CallGraph callGraph = cgs.getCurrentWorkspaceCallGraph(); // Look up a method vertex callGraph.getVertex("com/example/Foo", "process", "(Ljava/lang/String;)V") .ifPresent(vertex -> { System.out.println("Callers of process():"); vertex.getCallers().forEach(edge -> System.out.println(" <- " + edge.getCaller().getMethodName())); System.out.println("Callees of process():"); vertex.getCallees().forEach(edge -> System.out.println(" -> " + edge.getCallee().getMethodName())); }); ``` -------------------------------- ### Disassemble and Reassemble Bytecode with AssemblerPipeline Source: https://context7.com/col-e/recaf/llms.txt Utilize AssemblerPipelineManager to disassemble Java classes or methods into JASM text and reassemble modified JASM text back into bytecode. Requires importing assembler-related classes. ```java import software.coley.recaf.services.assembler.AssemblerPipelineManager; import software.coley.recaf.services.assembler.JvmAssemblerPipeline; import me.darknet.assembler.error.Result; import me.darknet.assembler.ast.ASTElement; AssemblerPipelineManager apm = recaf.get(AssemblerPipelineManager.class); JvmAssemblerPipeline pipeline = apm.getJvmAssemblerPipeline(); // Disassemble a class to JASM text ClassPathNode classPath = workspace.findClass("com/example/Foo"); Result disResult = pipeline.disassemble(classPath); disResult.ifOk(text -> System.out.println("Disassembled:\n" + text)); // Disassemble a single method ClassMemberPathNode methodPath = classPath.childMethod("add", "(II)I"); Result methodText = pipeline.disassemble(methodPath); ``` ```java // Parse and assemble modified JASM text back into a class String modifiedJasm = disResult.get().replace("return", "iconst_0\n return"); var tokenResult = pipeline.tokenize(modifiedJasm, "source"); if (tokenResult.isOk()) { var parseResult = pipeline.fullParse(tokenResult.get()); if (parseResult.isOk()) { List ast = parseResult.get(); Result assembled = pipeline.assembleAndWrap(ast, classPath); assembled.ifOk(newClass -> { workspace.getPrimaryResource().getJvmClassBundle() .put(newClass.getName(), newClass); System.out.println("Re-assembled: " + newClass.getName()); }); assembled.ifErr(errors -> errors.forEach(e -> System.err.println("Assemble error: " + e.getMessage()))); } } ``` -------------------------------- ### Accessing Raw Class Data with WorkspaceResource Source: https://context7.com/col-e/recaf/llms.txt The WorkspaceResource API allows access to various bundles of class data (JVM, Android, versioned) and embedded resources. It also provides functionality to modify and update classes within these bundles. ```java import software.coley.recaf.workspace.model.resource.WorkspaceResource; import software.coley.recaf.workspace.model.bundle.JvmClassBundle; import software.coley.recaf.info.JvmClassInfo; import software.coley.recaf.info.builder.JvmClassInfoBuilder; WorkspaceResource primary = workspace.getPrimaryResource(); // Access the primary JVM class bundle and iterate JvmClassBundle jvmBundle = primary.getJvmClassBundle(); for (JvmClassInfo cls : jvmBundle) { System.out.println(cls.getName() + " methods=" + cls.getMethods().size()); } // Versioned bundles for multi-release JARs primary.getVersionedJvmClassBundles().forEach((version, bundle) -> { System.out.println("Java " + version + " specific classes: " + bundle.size()); }); // Android DEX bundles primary.getAndroidClassBundles().forEach((dexName, bundle) -> { System.out.println(dexName + " has " + bundle.size() + " classes"); }); // Embedded resources (JARs inside a fat JAR) primary.getEmbeddedResources().forEach((name, embedded) -> { System.out.println("Embedded: " + name + " classes=" + embedded.getJvmClassBundle().size()); }); // Modify a class in the bundle (replaces old entry, triggers listeners) JvmClassInfo original = jvmBundle.get("com/example/Foo"); JvmClassInfo modified = original.toJvmClassBuilder() .adaptFrom(/* new bytecode */ original.getBytecode()) .build(); jvmBundle.put(modified.getName(), modified); ``` -------------------------------- ### Decompile Classes with DecompilerManager Source: https://context7.com/col-e/recaf/llms.txt Use DecompilerManager to decompile classes using the preferred or a specific decompiler. Custom bytecode pre-filters and output text post-filters can be registered. Available decompilers can be listed. ```java import software.coley.recaf.services.decompile.DecompilerManager; import software.coley.recaf.services.decompile.DecompileResult; import software.coley.recaf.info.JvmClassInfo; DecompilerManager dm = recaf.get(DecompilerManager.class); Workspace workspace = wm.getCurrent(); JvmClassInfo cls = (JvmClassInfo) workspace.findClass("com/example/Foo").getValue(); // Decompile using the preferred (selected) decompiler dm.decompile(workspace, cls) .thenAccept(result -> { if (result.getText() != null) { System.out.println("=== Decompiled Source ==="); System.out.println(result.getText()); } else { System.out.println("Decompilation failed"); } }); // Decompile with a specific registered decompiler by name var cfr = dm.getJvmDecompiler("CFR"); if (cfr != null) { DecompileResult r = dm.decompile(cfr, workspace, cls).join(); System.out.println("CFR config hash: " + r.getConfigHash()); } // Register a custom bytecode pre-filter (e.g., strip synthetic flags before decompiling) dm.addJvmBytecodeFilter((ws, classInfo, bytecode) -> { // transform bytecode bytes if needed return bytecode; }); // Register a custom output text post-filter dm.addOutputTextFilter((ws, classInfo, text) -> text.replace("synthetic", "/* synthetic */")); System.out.println("Available JVM decompilers: " + dm.getJvmDecompilers().stream() .map(d -> d.getName()).toList()); // Example output: Available JVM decompilers: [CFR, Fallback, Vineflower] ``` -------------------------------- ### Recompile Decompiled Source with JavacCompiler Source: https://context7.com/col-e/recaf/llms.txt Utilize JavacCompiler to recompile Java source code using the JDK's JavaCompiler with an in-memory file system. Supports custom compilation arguments like target version and debug information. Handles missing dependencies by generating phantom classes. ```java import software.coley.recaf.services.compile.JavacCompiler; import software.coley.recaf.services.compile.JavacArguments; import software.coley.recaf.services.compile.JavacArgumentsBuilder; import software.coley.recaf.services.compile.CompilerResult; import software.coley.recaf.services.compile.CompilerDiagnostic; JavacCompiler compiler = recaf.get(JavacCompiler.class); Workspace workspace = wm.getCurrent(); String source = """ package com.example; public class Foo { public int add(int a, int b) { return a + b; } } """ JavacArguments args = new JavacArgumentsBuilder() .withClassName("com/example/Foo") .withClassSource(source) .withVersionTarget(17) // compile targeting Java 17 .withDebugVariables(true) .withDebugLines(true) .build(); CompilerResult result = compiler.compile(args, workspace, null); if (result.wasSuccess()) { result.getCompilations().forEach((name, bytecode) -> { System.out.println("Compiled: " + name + " (" + bytecode.length + " bytes)"); // Put the new bytecode back into the workspace bundle JvmClassBundle bundle = workspace.getPrimaryResource().getJvmClassBundle(); bundle.put(name, new JvmClassInfoBuilder().withBytecode(bytecode).build()); }); } else { for (CompilerDiagnostic diag : result.getDiagnostics()) { System.out.printf("[%s] Line %d: %s%n", diag.getLevel(), diag.getLine(), diag.getMessage()); } } // Output: Compiled: com/example/Foo (342 bytes) ``` -------------------------------- ### Manage Comments with CommentManager Source: https://context7.com/col-e/recaf/llms.txt Use CommentManager to attach persistent developer notes to classes, fields, and methods within a workspace. Comments are stored per workspace and survive Recaf sessions. ```java import software.coley.recaf.services.comment.CommentManager; import software.coley.recaf.services.comment.WorkspaceComments; import software.coley.recaf.services.comment.ClassComments; CommentManager cm = recaf.get(CommentManager.class); WorkspaceComments wsComments = cm.getOrCreateWorkspaceComments(workspace); ClassComments classComments = wsComments.getOrCreateClassComments("com/example/Foo"); classComments.setClassComment("Main entry point for the obfuscated loader"); classComments.setFieldComment("a", "I", "Stores decryption key"); classComments.setMethodComment("b", "()V", "Calls the payload"); System.out.println("Class comment: " + classComments.getClassComment()); // Output: Class comment: Main entry point for the obfuscated loader System.out.println("Field comment: " + classComments.getFieldComment("a", "I")); // Output: Field comment: Stores decryption key ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.