{"id":16375004,"url":"https://github.com/moderocky/mirror","last_synced_at":"2025-03-23T03:32:40.789Z","repository":{"id":54342311,"uuid":"337092614","full_name":"Moderocky/Mirror","owner":"Moderocky","description":"A smart, fast alternative to Java's reflection API.","archived":false,"fork":false,"pushed_at":"2023-03-27T14:56:58.000Z","size":204,"stargazers_count":34,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-18T17:07:58.878Z","etag":null,"topics":["bytecode","bytecode-manipulation","java","reflection","reflection-library"],"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/Moderocky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-08T13:54:48.000Z","updated_at":"2025-02-08T10:19:39.000Z","dependencies_parsed_at":"2024-10-28T15:23:32.381Z","dependency_job_id":null,"html_url":"https://github.com/Moderocky/Mirror","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FMirror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FMirror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FMirror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FMirror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Moderocky","download_url":"https://codeload.github.com/Moderocky/Mirror/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245052630,"owners_count":20553161,"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","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":["bytecode","bytecode-manipulation","java","reflection","reflection-library"],"created_at":"2024-10-11T03:19:05.441Z","updated_at":"2025-03-23T03:32:40.274Z","avatar_url":"https://github.com/Moderocky.png","language":"Java","readme":"Mirror\n=====\n\n### Opus #4\n\nA smart, simple and fast alternative to Java's clunky reflection API.\nThis is potentially the fastest access API possible, avoiding all slow security checks.\n\nVersion 5 of Mirror abandoned trying to shortcut the JDK's reflection API and instead compiles direct access routes, using the most efficient method possible.\n\n## Maven Information\n```xml\n\u003crepository\u003e\n    \u003cid\u003ekenzie\u003c/id\u003e\n    \u003cname\u003eKenzie's Repository\u003c/name\u003e\n    \u003curl\u003ehttps://repo.kenzie.mx/releases\u003c/url\u003e\n\u003c/repository\u003e\n``` \n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003emx.kenzie\u003c/groupId\u003e\n    \u003cartifactId\u003emirror\u003c/artifactId\u003e\n    \u003cversion\u003e5.0.3\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n## Introduction\n\nMirror provides an alternative to Java's reflection and MethodHandles API with better efficiency and less boilerplate.\n\nRather than breaking security and injecting the code into the class's namespace to see private members, Mirror uses Java's `invokedynamic` opcode to access the member directly. This involves writing a miniature accessing class at runtime, but these class stubs are automatically cached and reused whenever an accessor is created to reduce overhead.\n\nAlthough it uses a fairly similar process to Java's internal accessor system, Mirror gains some speed advantages through minor time-saves. Every `invoke` call to a reflection object involves:\n1. More than seven recursive security checks.\n2. A tree-lookup to find the internal accessor.\n3. At least two delegated `invoke` calls to internal accessors.\n\nMirror avoids all of this by:\n- Performing the invocation in-situ.\n- Not performing any pointless security checks.\n- Using the fastest instruction possible in the situation.\n\nA lot of reflection API use is to access members not available at compile-time, especially if the class name or version isn't known, or if the class is unavailable as a dependency. In these cases, the actual member isn't private and so a lot of the overhead is wasted, making reflection significantly slower than normal invocation.\nMirror avoids this by writing a normal invocation call where possible, meaning the only difference between using the accessor and calling the method directly is a tiny method call and `checkcast` instructions for mismatched parameters.\n\nThe timings below are based on running the speed check in `BasicTest` on my laptop.\n\n| Access Type                         | Average Speed |\n|-------------------------------------|---------------|\n| Normal Invocation                   | ~4ns          |\n| Access Public Member                | ~6ns          |\n| Access Hidden Member                | ~40ns         |\n| Access Member via `Mirror#unsafe()` | ~80ns         |\n| Magic Mirror Invocation             | ~40ns         |\n| ~~Reflection~~ (JDK)                | ~220ns        |\n| ~~Proxy Invocation~~ (JDK)          | ~1300ns       |\n\n## Migrating from v4.0.0\n\nVersion 5 removes all alternative mirror types, and in return provides a much safer implementation of v4's 'fast mirror'.\n\nAn object or class is first targeted with `Mirror.of(thing)`, from which special 'accessors' can be created to use particular fields, methods and constructors.\n\n## Magic Mirrors\n\nMagic mirrors are a feature borrowed from Mirror v4, allowing the smart binding of user-defined interface methods to hidden methods. These are slower than normal method accessors, though still faster than using Java reflection.\n\nMagic mirrors originally used Java's proxy system internally (which has a lot of needless bloat) but in Mirror v5 they were switched over to [Mimic](https://github.com/Moderocky/Mimic) which is a significantly faster and more adaptive replacement for proxies.\n\nThe magic mirror implementation in v4 used a proxy, performed a table lookup and then called the method invoker, costing around `2000` nanoseconds.\nWhen switching to the v5 MethodAccessors and improving the table lookup, this was reduced to `1200` nanoseconds.\nAfter switching from Java's proxies to [Mimic](https://github.com/Moderocky/Mimic), this process was reduced to `200` nanoseconds, almost six times faster than proxies.\nBy hardcoding the method calls to remove the table lookup and bridge call entirely, this averages at `33` nanoseconds and is comparable to using the MethodAccessor directly, meaning it takes a little more than 1.5% of the time that v4 took.\n\nThis means that for the first time ever, magic mirrors are a viable alternative in performance-dependent projects and implementations, especially those requiring a lot of repetitive calls which can benefit from JIT.\n\nAnother benefit of using Mimic is that the magic mirrors can use non-final default classes as templates, increasing developer freedom.\n\n```java \ninterface Test {\n    int thing(int i); // mapped to a thing(I)I method on the target object\n}\nfinal Test test = Mirror.of(object)\n    .magic(Test.class);\nassert test.thing(3) == 5;\n```\n\n## Intrinsic Magic Mirrors\n\nIntrinsic magic mirrors are the fastest possible way to repetitively call a member, consistently outperforming everything other than directly accessing the member itself.\n\nThis speed is achieved by removing as much as possible from the call, making it an almost-direct invocation of the object itself. The overhead for accessing a non-private member is under five nanoseconds, requiring only an `xload` bytecode instruction and a method call. \nThe target handle is baked directly into the method implementation, removing the need to retrieve an accessor by index and call it.\n\nAs a result these have a lot less security and will throw critical errors if parameters or other type information is incorrect. As they use a provided class erasure, they cannot be calculated dynamically like MethodAccessors can, so they will not be suitable in cases where target erasure is unknown at compile-time. Boxing and type conversion is also unsupported.\n\nIntrinsic magic mirrors also support field access through the `$` prefix before a method name.\n\n```java \ninterface Magic {\n    int $number(); // retrieves the 'number' field - static or dynamic\n    \n    void $number(int i); // sets the 'number' field - static or dynamic\n}\n\nfinal Magic magic = Mirror.of(object).magicIntrinsic(Magic.class);\nmagic.$number(5);\nassert magic.$number() == 5;\n```\n\n## Accessing Named Modules\n\nJava 17+ has tried to make it impossible to access private members in named modules (such as `jdk.internal` resources.)\nAs some libraries depend on these, Mirror v5 has a way of accessing them. This is a particularly **dangerous** method, so it is advised not to be used unless absolutely necessary.\n\nBy default, Mirror will attempt to inject the accessor into whatever class-loader the target member is provided by, and then exports the accessor to the caller class.\nThis will allow access to named modules and even JDK internals, which reflection would not.\n\nIf this is not sufficient (for example, if a module has some way of blocking the export process) an accessor-chain can be used. This creates two separate accessors: an out-facing one is placed within some accessible namespace of the target module (the module must have *some* open-facing attachment point in order to be running within the same JVM as your code) and a bridge is placed in an intermediary namespace, relaying the access calls.\n\nCalling the `unsafe` method on a mirror will replace the code-writer with one capable of building these chain-calls, but is only accessible in an environment where Java's `Unsafe` is accessible, since this is needed to access the native bootstrap classloader and inject the accessors.\n\nGenerally speaking, this chain version will not be necessary - even internal JDK modules are accessible via the smart export system.\n\n```java \nfinal MethodAccessor\u003cClass\u003c?\u003e[]\u003e accessor = Mirror.of(Class.class)\n    .unsafe()\n    .method(\"getInterfaces0\");\nfinal Class\u003c?\u003e[] interfaces = accessor.invoke();\nassert interfaces[0] == Serializable.class;\n```\n\nUsing this unsafe behaviour is not recommended, but may be necessary for applications that previously depended on reflection to access secret JDK internals.\n\n## Examples\n\nGetting and using a method accessor:\n```java \nfinal MethodAccessor\u003c?\u003e method = Mirror.of(System.out).method(\"println\", String.class);\nmethod.invoke(\"hello\");\n```\n\nUsing a method accessor in-line without a variable:\n```java \nMirror.of(System.out)\n    .method(\"println\", String.class)\n    .invoke(\"hello\");\n```\n\nUsing the return value of a method accessor:\n```java \nlong value = (long) Mirror.of(System.class)\n    .method(\"nanoTime\")\n    .invoke(); // the long primitive will be wrapped as a Long\nassert value \u003e -1;\n```\n\nGetting a field accessor and using its value:\n```java \nfinal FieldAccessor\u003cPrintStream\u003e field = Mirror.of(System.class).field(\"out\");\nfield.get().println(\"hello\");\n// the explicit \u003cPrintStream\u003e type allows us to directly call .println\n```\n\nFast-mirroring a field value:\n```java \nMirror.of(System.class)\n    .field(\"out\")\n    .mirror() // Calls Mirror.of on the field value\n    .method(\"println\", int.class)\n    .invoke(2); // Boxed Integer is automatically unboxed \n```\n\nSetting a field value:\n```java \nMirror.of(this)\n    .field(\"word\")\n    .set(\"bean\");\n```\n\nUsing a constructor mirror:\n```java \nMirror.of(ConstructorAccessorTest.TestConstructor.class)\n    .constructor(int.class, int.class)\n    .newInstance(0, 0);\n```\n\nCreating and using a simple magic mirror:\n```java \ninterface MyTemplate {\n    void myMethod(int i, int j);\n    void myMethod(int i);\n}\nfinal MyTemplate template = Mirror.of(object)\n    .magic(MyTemplate.class);\ntemplate.myMethod(6, 6);\ntemplate.myMethod(3);\n```\n\nCreating an advanced intrinsic magic mirror:\n```java \ninterface Magic {\n    int $number(); // retrieves the 'number' field\n    void $number(int i); // sets the 'number' field\n    \n    String getName();  // invokes the 'getName' method on the target\n}\n\nfinal Magic magic = Mirror.of(object).magicIntrinsic(Magic.class);\nmagic.$number(5);\nassert magic.$number() == 5;\nassert magic.getName().equals(\"Henry\");\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Fmirror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoderocky%2Fmirror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Fmirror/lists"}