{"id":28619660,"url":"https://github.com/eleme/intimate","last_synced_at":"2025-07-06T21:36:35.677Z","repository":{"id":145526848,"uuid":"116007600","full_name":"eleme/Intimate","owner":"eleme","description":"Intimate 提供了友好的 API 让 java 反射的使用更加简单平滑。  其最核心的价值在于 Intimate 将在编译期对 apk 内部代码的调用进行反射优化，完全免除反射的效率问题，使得反射调用就像普通调用一样快捷且无任何代价。","archived":false,"fork":false,"pushed_at":"2018-02-07T12:55:22.000Z","size":402,"stargazers_count":202,"open_issues_count":0,"forks_count":33,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-06-12T04:48:54.963Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eleme.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-01-02T11:20:30.000Z","updated_at":"2025-02-07T17:35:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"2b114b68-e5c8-4c9c-8e6e-29db36f96cfb","html_url":"https://github.com/eleme/Intimate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eleme/Intimate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2FIntimate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2FIntimate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2FIntimate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2FIntimate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eleme","download_url":"https://codeload.github.com/eleme/Intimate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eleme%2FIntimate/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263976332,"owners_count":23538484,"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":[],"created_at":"2025-06-12T04:40:54.120Z","updated_at":"2025-07-06T21:36:35.642Z","avatar_url":"https://github.com/eleme.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Intimate\n\nIntimate provides a friendly API to make Java reflection easier and more smooth.\n\nIts core value is optimizing the reflection call at compile time, which completely save reflection search time，and make a reflection call as fast as a normal call.\n\n\n*' Intiamte only take action on the code that you write and the library introduced（contains android.support.*）. But the system code will not be affected'*\n\n[中文 README](https://github.com/ELELogistics/Intimate/blob/master/README_zh.md)\n\n## Usage\n\nFirstly, add following code in root `build.gradle` of your project.\n\n```\ndependencies{\n    classpath 'me.ele:intimate-plugin:1.0.2'\n}\n```\n\nAnd then, add following code in your application module's `build.gradle`\n\n```\napply plugin: 'intimate-plugin'\n\ndependencies {\n    compile 'me.ele:intimate:1.0.2'\n    annotationProcessor 'me.ele:intimate-compiler:1.0.2'\n}\n```\n\n## The sample\n\n\nClasses that are expected to reflect：\n\n```\npublic class User {\n\n    private String name;\n    private int age;\n\n    public User(String name, int age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    private void setAge(int a, int b) {\n        this.age = a + b;\n    }\n\n}\n```\n\nUse the interface to describe what your need for reflection：\n\n```\n@RefTarget(clazz = User.class, optimizationRef = true)\npublic interface RefUser {\n\n    @GetField(\"name\")\n    String getName();\n\n    @SetField(\"name\")\n    void setName(String value);\n\n    @GetField(\"age\")\n    int getAge();\n\n    @Method\n    void setAge(int a, int b);\n    \n}\n```\n\nUse `RefImplFactory` to create `RefUser` instance. Then, you can access any field or method of an object through the `RefUser`.\n\n```\nUser user = new User(\"papapa\", \"man\", 19, \"Class 3\");\nRefUser refUser = RefImplFactory.getRefImpl(user, RefUser.class);\nif(refUser != null){\n\n    assertEquals(refUser.getName(), \"papapa\");\n    refUser.setName(\"kaka\");\n    assertEquals(refUser.getName(), \"kaka\");\n\n    assertEquals(refUser.getAge(), 19);\n    refUser.setAge(19,1);\n    assertEquals(refUser.getAge(), 20);\n    \n}\n```\n\n## API\n\n#### @RefTarget    @RefTargetForName\n\n```\npublic @interface RefTarget {\n\n    Class clazz();\n    \n    boolean optimizationRef();\n}\n\npublic @interface RefTargetForName {\n\n    String className();\n    \n    boolean optimizationRef();\n}\n```\n\n`@RefTarget` and `@RefTargetForName` describe the target class to be reflected. I call her `RefInterface`.\n\n`@RefTarget（clazz=XXX.class)` \n\n'xxx.class' is your target class. When it is a private class or inner class，form which you can't get `Class` object, you can use `@RefTargetForName(className=\"xxx.xxx.xx\")`, where 'xxx.xxx.xxx' is class canonical name.\n\nIntimate can optimize the reflection call at compile time, which completely save reflection search time，and make a reflection call as fast as a normal call\n\nso, for Android system class, java.lang.* and etc., `optimizationRef` value should be false.\n\nThe sample：\n\n```\n@RefTarget(clazz = RecyclerView.class, optimizationRef = true)\npublic interface RefRecyclerView {\n\n    @GetField(\"mLastTouchY\")\n    int getLastTouchY();\n\n    @SetField(\"mLastTouchY\")\n    void setLastTouchY(int itemsChanged);\n}\n\n@RefTargetForName(className = \"android.view.View$ListenerInfo\", optimizationRef = false)\npublic interface RefListenerInfo {\n\n    @GetField(\"mOnClickListener\")\n    View.OnClickListener getListener();\n\n}\n\n\n```\n\n**To avoid unnecessary reflection search, the value of optimizationRef is highly recommended to be true. But when System class use `optimizationRef = true`, the build will fail.**\n\n\n**You should use `@RefTarget(clazz = XXX.class）` as much as possible**, because `@RefTargetForName(className = \"xxx.xx.xxx.class\"）` will use `Class.forName(\"xxx.xx.xxx.class\")`, you should avoid such an operation.\n\n \n#### @GetField    @SetField\n\n```\npublic @interface GetField {\n\n    String value();\n    \n}\n\npublic @interface SetField {\n\n    String value();\n    \n}\n\n```\n\n`@GetField` `@SetField` Describes the `get` and `set` of Class field.\n\n`value` is field name.\n\nIntimate determined field type through `@GetField` annotation method's returnType.\n\nIntimate determined field type through `@SetField` annotation method's parameterType.\n\nSpecial instructions: when te field type is private Class or inner class, you can convert the returnType or parameterType to Object.\n\n```\n@GetField(\"name\")\nString getName();\n\n@SetField(\"age\")\nvoid setName(int age);\n\n@SetField(\"user\")\nvoid setUser(Object user);\n```\n\nIn the example above, Intimate know the target is [java.lang.String : name], [int : age] and [Object : user]\n\n#### @Method\n\n```\npublic @interface Method {\n    String value() default \"\";\n}\n```\n\n`@Method` Describes the 'method' \n\n`value` is method name which can be omitted. When it's omitted，Intimate deduces method name through `@Method` annotation.\n\nIntimate will find the function with signature matching the one annotated by `@Method`. (with same returnType, methodName, parameterList)\n\nSpecial instructions: when te field type is private Class or inner class, you can convert the returnType or parameterType to Object.\n\nBoth correct and wrong examples are shown as follows.\n\nTarget Class：\n\n```\nclass User {\n    int calculateAge(int year) {\n        return 2018 - year;\n    }\n}\n\n```\n\n```\n//matching User - calculateAge(int) \n@Method\nint calculateAge(int year);\n\n//matching User-calculateAge(int) \n@Method(\"calculateAge\")\nint getAge(int year);\n\n//User don't have getAge(int)，matching failure, build failure\n@Method\nint getAge(int year);\n\n//User don't have calculateAge(int,int)，matching failure, build failure\n@Method\nint calculateAge(int year,int month);\n```\n\n#### Exception handling\n\nBy default, when `optimizationRef = false`, Intimate will catch all exception.\nwhen `optimizationRef = true`, if can't find field or method and build will fail.\n\nwhen `optimizationRef = false`,you need handle some exception, you can do that:\n\n```\n@GetField(\"mListenerInfo\")\nObject getListenerInfo() throws IllegalAccessException, NoSuchFieldException;\n    \n```\n`getListenerInfo()` will throw IllegalAccessException or NoSuchFieldException, Intimate catch other exception.\n\n#### Create RefInterface instance\n\nyou can use `RefImplFactory.getRefImpl` to create RefInterface instance:\n\n```\n\npublic class RefImplFactory {\n    public static \u003cT\u003e T getRefImpl(Object object, Class clazz){...}\n}\n\n```\n\n```\nRefTextView refTextView = RefImplFactory.getRefImpl(textView, RefTextView.class);\n\n```\n\n#### Cache managerment\n\nWhen `@RefTarget(optimizationRef = false)` or `@RefTargetForName(optimizationRef = false)`，Intimate will cache Field and Method, so the Intimat requires only one reflection search.\n\nIf you don't need reflection on some class any more，cache could be cleaned. The parameter is RefInterface class.\n\n```\npublic class RefImplFactory {\n\n    public static void clearAccess(Class refClazz){...}\n    \n    public static void clearAllAccess(){...}\n}\n\n```\n\nThe sample：\n\n```\nRefImplFactory.clearAccess(RefTextView.class);\n\nRefImplFactory.clearAllAccess()；\n```\n\nWhen `@RefTarget(optimizationRef = false)`  or `@RefTargetForName(optimizationRef = false)`, cache is disabled and you don't need to clear it.\n\n#### Special sample\n\nSpecial situations require special gestures.\n\nTarget Class：\n\n```\nclass View {\n\n\t...\n    static class ListenerInfo {\n    \t...\n        public OnClickListener mOnClickListener;\n    }\n\n}\n\n```\nWhen you get  `OnClickListener mOnClickListener`，Single RefInterface may not fulfill your requirements,  you need two.\n\n```\n@RefTarget(clazz = TextView.class, optimizationRef = false)\npublic interface RefTextView {\n\n    @GetField(\"mListenerInfo\")\n    Object getListenerInfo() throws IllegalAccessException, NoSuchFieldException;\n    \n}\n\n@RefTargetForName(className = \"android.view.View$ListenerInfo\", optimizationRef = false)\npublic interface RefListenerInfo {\n\n    @GetField(\"mOnClickListener\")\n    View.OnClickListener getListener();\n    \n}\n```\n\nclient:\n\n```\nTextView textView = new TextView(context);\nRefTextView refTextView = RefImplFactory.getRefImpl(textView, RefTextView.class);\n\nRefListenerInfo refListenerInfo = RefImplFactory.getRefImpl(refTextView.getListenerInfo(), RefListenerInfo.class);\n\nView.OnClickListener listener = refListenerInfo.getListener();\n```\n\n## ProGuard\n\nYou should ensure that your target class will not be obfuscated or that the target class and its attributes will not be found.\n\n## Tips:\n\n- Inner class should be named like `package.outer_class$inner_class`\n- To avoid unnecessary reflection search, the value of optimizationRef is highly recommended to be true. But when System class use `optimizationRef = true`, the build will fail.\n- when te field type is private Class or inner class, you can convert the returnType or parameterType to Object.\n- To get some private class or inner class object,you can use multiple RefInterface.\n- You can visit the link to learn more. [app/src/androidTest/](https://github.com/ELELogistics/Intimate/tree/master/app/src/androidTest/java/me/ele/example)\n- **If Aspectjx executes first, the Intimate may be invalid**\n\n## License\n\n\u003cimg alt=\"Apache-2.0 license\" src=\"https://lucene.apache.org/images/mantle-power.png\" width=\"128\"\u003e\n\nIntimate is available under the Apache-2.0 license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feleme%2Fintimate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feleme%2Fintimate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feleme%2Fintimate/lists"}