{"id":27432339,"url":"https://github.com/justhm228/dynagent","last_synced_at":"2025-10-24T22:40:39.501Z","repository":{"id":209514418,"uuid":"723466206","full_name":"JustHm228/Dynagent","owner":"JustHm228","description":"A lightweight solution to dynamically attach a Java agent to the current VM","archived":false,"fork":false,"pushed_at":"2025-03-12T18:45:36.000Z","size":90,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-04T02:47:01.197Z","etag":null,"topics":["agent","instrumentation","java","java-agent","java-agents","java-instrumentation","java-library","javaagent","library","lightweight"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JustHm228.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-11-25T18:56:19.000Z","updated_at":"2025-04-25T17:43:01.000Z","dependencies_parsed_at":"2025-06-03T18:41:23.077Z","dependency_job_id":"8ce7f421-bf0f-40ec-9762-b1aa1adb42f7","html_url":"https://github.com/JustHm228/Dynagent","commit_stats":null,"previous_names":["justhm228/dynagent"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JustHm228/Dynagent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustHm228%2FDynagent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustHm228%2FDynagent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustHm228%2FDynagent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustHm228%2FDynagent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JustHm228","download_url":"https://codeload.github.com/JustHm228/Dynagent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustHm228%2FDynagent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280878345,"owners_count":26406641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","instrumentation","java","java-agent","java-agents","java-instrumentation","java-library","javaagent","library","lightweight"],"created_at":"2025-04-14T16:46:28.861Z","updated_at":"2025-10-24T22:40:39.461Z","avatar_url":"https://github.com/JustHm228.png","language":"Java","readme":"# Dynagent\n\n**Dynagent** _(**Dyn**amic Java **agent**)_ is a small, very lightweight library which allows you to\ndynamically attach a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) to\nthe current virtual machine. This allows you to take a valid `Instrumentation` instance and use all of\nits functionality without having to use additional command line options on application startup.\nHere is an example:\n\n```java\nif (Dynagent.install()) {\n\t\n\tfinal Instrumentation agent = Dynagent.getAgent();\n\t\n\t// Do anything you want with `agent`...\n\t\n} else {\n\n        // Failed to attach!\n}\n```\n\nDynagent will take care of the rest, allowing you to completely focus on your code.\n\n## Overview\n\n[Java agents](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)\ncan be very useful in solving some very special cases. In particular, they're useful for the bytecode\nmanipulation. These tasks require attaching a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) to\nthe current process.\n\n### Alternatives\n\nThe problem of attaching a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) to\nthe current process is usually solved either by initially specifying the appropriate JVM option (which\nmay not be very practical because JVM options aren't up to you), or by restarting the current process\nto attach it. This library was developed by me as an alternative solution when I was working on another\nproject that required a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) to be\ndynamically attached to the current process, but with conditions that prevented me from using the above\nsolutions.\n\n### Used Implementation\n\nInitially, I thought to use the\n[Attach API](\u003chttps://www.baeldung.com/java-instrumentation#dynamic-load\u003e), but I found that it can't\nattach a Java agent to the current process. Then I thought to launch a separate process and through it\nattach a Java agent to the current process. It sounded difficult, but... it worked. After several\nimprovements I was able to optimize the code and save it all in a single jar file. This library uses\na slightly modified implementation of that thing, but the algorithm hasn't changed significantly.\nThe attaching is still works this way:\n\n1. Find a valid `java` binary to run a temporary process.\n2. Dynamically create a temporary `.jar` file which will be a Java agent to be attached.\n3. Dynamically create a temporary `.jar` file which will attach a Java agent to the current process.\n4. Run a temporary process of an \"attacher\" `.jar` file and wait until it finishes.\n5. Check if we have a valid `Instrumentation` instance now.\n6. Delete temporary files.\n\nThe [Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)\nitself is stored in the class `DynagentImpl` from the library's `internal` package, and the \"attacher\"\nis stored in the class `DynagentInstaller` from the same package. **Direct access to the internal API\nisn't recommended** because the internal API can change a lot.\n\n### Dependencies\n\n- [Java](\u003chttps://www.oracle.com/java/technologies/downloads/#java21\u003e) 21\n- [JUnit5](\u003chttps://junit.org/junit5/\u003e) _(only required to perform unit tests)_\n\n## Quick Start\n\n**Please note that Dynagent has a simple built-in security system that allows you to explicitly set\nwhich classes will have access to the attached\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)'s\ninterface, because the implementation of\n[Java agents](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)\nbypasses all Java security checks and can be very dangerous. Therefore, when calling any method except\n`Dynagent.install()` and `Dynagent.isInstalled()`, the caller class will be checked. If the caller class\ndoesn't exist, cannot be checked, or isn't white-listed, an `IllegalCallerException` will be thrown!**\nWhen calling the `Dynagent.install()` method, you can specify, separated by commas, the classes that\nwill be allowed use to the installed\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)\n(the caller class always can use it), and if the Java agent hasn't yet been installed, it'll be\ninstalled and the specified classes will have permission to use it!\n\nTo attach a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e),\nyou should call the `Dynagent.install()` method. If the\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e)\nhasn't yet been attached, it will attach it and return `true` if the installation was successful,\nbut if it has already been attached, it will always return `true`. If you need to find out whether a\n[Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) has\nalready been attached without attaching it, then you should call the `Dynagent.isInstalled()` method.\nThen, to get the `Instrumentation` instance, you just need to call the `Dynagent.getAgent()` method.\nAfter this, you can do whatever your heart desires with the resulting copy of `Instrumentation`!\n\nBut also, the class `Dynagent` itself contains several static methods that allow you to perform any\noperation with `Instrumentation` without having its instance:\n\n- `Dynagent.getObjectSize(Object)`. Returns the memory size allocated for the specified object.\n- `Dynagent.isModifiableModule(Module)`. Checks if you can redefine the specified module.\n- `Dynagent.redefineModule(Module, Set, Map, Map, Set, Map)`. Adds the specified dependencies to the\n  module if it's a modifiable module.\n- `Dynagent.appendToBootstrapClassLoaderSearch(JarFile)`. Adds the specified jar file to the boot class\n  path.\n- `Dynagent.appendToSystemClassLoaderSearch(JarFile)`. Adds the specified jar file to the class path.\n- `Dynagent.getAllLoadedClasses()`. Returns an array of all loaded classes currently loaded by the JVM,\n  including hidden classes, anonymous classes, lambda classes, primitive types and array types.\n- `Dynagent.getInitiatedClasses(ClassLoader)`. Returns an array of all loaded classes which can be\n  discovered by its name from the specified class loader and its parents, which doesn't include hidden\n  classes, interfaces and array types whose element type is a hidden class or an interface.\n- `Dynagent.isModifiableClass(Class)`. Checks if you can redefine the specified class.\n- `Dynagent.isRetransformClassesSupported()`. Checks if the class retransformation is supported in the\n  current environment.\n- `Dynagent.isRedefineClassesSupported()`. Checks if the class redefinition is supported in the current\n  environment.\n- `Dynagent.isNativeMethodPrefixSupported()`. Checks if the native method prefix is supported in the\n  current environment.\n- `Dynagent.redefineClasses(ClassDefinition[])`. Redefines all specified classes with the specified\n  bytecode.\n- `Dynagent.redefineClasses(ClassDefinition)`. Redefines a single class with the specified bytecode.\n- `Dynagent.redefineClasses(Class, File)`. Redefines a single class with a bytecode from the specified\n  file.\n- `Dynagent.redefineClasses(Class, InputStream)`. Redefines a single class with a bytecode from the\n  specified input stream.\n- `Dynagent.redefineClasses(Class, ByteBuffer)`. Redefines a single class with a bytecode from the\n  specified byte buffer.\n- `Dynagent.redefineClasses(Class, byte[], int, int)`. Redefines a single class with a bytecode from the\n  specified byte array (with offset and length).\n- `Dynagent.redefineClasses(Class, byte[])`. Redefines a single class with a bytecode from the specified\n  byte array.\n\nMore such methods will be added in the future!\n\n## Future Plans\n\nLong-term support for such a simple project shouldn't be difficult and will continue to develop (at\nleast as long as my other projects uses it). You just have to wait!\n\n- [x] Come up with an idea.\n- [x] Implement the idea.\n- [ ] Improve/optimize the current implementation.\n-\n  - [ ] _Should I [lock](\u003chttps://docs.oracle.com/javase/8/docs/api/java/nio/channels/FileLock.html\u003e)\n    temporary files?.._\n- [ ] Make the built-in security system more flexible.\n- [ ] ~~Add built-in support for bytecode manipulation frameworks like [ASM](\u003chttps://asm.ow2.io\u003e),\n  [ByteBuddy](\u003chttps://bytebuddy.net\u003e) and [Javassist](\u003chttps://www.javassist.org\u003e).~~\n- [ ] Publish to Maven.\n- [ ] Try to create a custom, more performant `Instrumentation` implementation using native JVM functions,\n  i.e. without resource-intensive dynamic attaching of the\n  [Java agent](\u003chttps://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html\u003e) to\n  the current process.\n\n## License\n\nThe source code of Dynagent is licensed under [MIT](./LICENSE):\n\n```text\nMIT License\n\nCopyright (c) 2023-2025 JustHuman228\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjusthm228%2Fdynagent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjusthm228%2Fdynagent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjusthm228%2Fdynagent/lists"}