{"id":15050656,"url":"https://github.com/cmhteixeira/delegate-macro","last_synced_at":"2025-04-10T02:16:22.430Z","repository":{"id":57718299,"uuid":"329430173","full_name":"cmhteixeira/delegate-macro","owner":"cmhteixeira","description":"Annotation to automatically delegate/proxy implementation of interface to dependency  ","archived":false,"fork":false,"pushed_at":"2021-07-05T21:07:54.000Z","size":234,"stargazers_count":12,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T02:16:15.990Z","etag":null,"topics":["delegate-pattern","macro","proxy-pattern","scala"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmhteixeira.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-13T20:59:34.000Z","updated_at":"2022-04-10T11:52:55.000Z","dependencies_parsed_at":"2022-09-14T22:42:03.572Z","dependency_job_id":null,"html_url":"https://github.com/cmhteixeira/delegate-macro","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmhteixeira%2Fdelegate-macro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmhteixeira%2Fdelegate-macro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmhteixeira%2Fdelegate-macro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmhteixeira%2Fdelegate-macro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmhteixeira","download_url":"https://codeload.github.com/cmhteixeira/delegate-macro/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248142906,"owners_count":21054671,"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":["delegate-pattern","macro","proxy-pattern","scala"],"created_at":"2024-09-24T21:28:46.675Z","updated_at":"2025-04-10T02:16:22.383Z","avatar_url":"https://github.com/cmhteixeira.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Delegate Macro \u0026emsp; [![Build Status](https://www.travis-ci.com/cmhteixeira/delegate-macro.svg?branch=master)](https://www.travis-ci.com/cmhteixeira/delegate-macro) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.cmhteixeira/delegate-macro_2.13/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.cmhteixeira/delegate-macro_2.13)\n\n**Found the project interesting?** \u0026rightarrow;  Then drop a :star:. I am needing the encouragement. ;)  \n**Found a problem?** \u0026rightarrow; Open an issue, and I will look into it ASAP.  \n**Want to contribute?** \u0026rightarrow; If you found a bug and want to fix it yourself open an MR.  I welcome contributions.  \n\n## Motivation\n\nThis macro enables you to delegate/proxy the implementation of an interface to a dependency in a very straightforward\nway. It saves you from the tedious work of doing it manually when the interface is very large.\n\n### Why would you want to do that?\n\nA good use case is helping you implement the delegate (a.k.a. proxy) pattern. This pattern is useful when you have a\nclass over which you want to have some control. Therefore, you wrap it in your own custom class, and manage access\nexplicitly. Let's say you want to control access to *_a subset_* of the methods of a jdbc connection. For example, you\nwant to log each time someone sets the schema. You don't want to implement `java.sql.Connection` yourself; least of all\nbecause there would be a lot of code duplication. So you create a custom wrapper class to which you manually inject an\nknown implementation like `com.mysql.cj.jdbc.ConnectionImpl`, and then delegate all behaviour except that particular\nmethod you want to log:\n\n```scala\nclass MyLoggingConnection(coreConnection: java.sql.Connection, logger: Logger) extends java.sql.Connection {\n  // manually delegate everything else (over 50 other methods)\n  def setSchema(schema: String): Unit = {\n    logger.log(\"Someone is setting the schema\")\n    coreConnection.setSchema(schema)\n  }\n}\n```\n\nThe downside of this is that for interfaces with dozens of methods, you have to delegate manually which is tedious and\nerror prone. More importantly, the intent of your custom wrapper class is lost amongst a sea of other methods.\n\nWith this macro annotation, the delegation part is done auto-magically.\n\n## How to use\n\nApply this macro to a class that implements an interface. At compile-time, the macro will implement the interface\nmethods on your class using a dependency that you inject on that class, with the exception of the methods you implement\nmanually on the source code.\n\n### Example\n\n```scala\nimport com.cmhteixeira.delegatemacro.Delegate\n\ntrait Connection {\n  def method1(a: String): String\n\n  def method2(a: String): String\n\n  // 96 other abstract methods\n  def method100(a: String): String\n}\n\n@Delegate\nclass MyConnection(delegatee: Connection) extends Connection {\n  def method10(a: String): String = \"Only method I want to implement manually\"\n}\n\n// The source code above would be equivalent, after the macro expansion, to the code below\nclass MyConnection(delegatee: Connection) extends Connection {\n  def method1(a: String): String = delegatee.method1(a)\n\n  def method2(a: String): String = delegatee.method2(a)\n\n  def method10(a: String): String = \"Only method I need to implement manually\"\n\n  // 96 other methods that are proxied to the dependency delegatee\n  def method100(a: String): String = delegatee.method100(a)\n}\n\n```\n\n## Support\n\nThe artefacts have been uploaded to Maven Central. Alternatively, they are also available on the GitHub registry.\n\n| Library Version | Scala 2.11 | Scala 2.12 | Scala 2.13 |\n|---------|------------|------------|------------|\n| 0.3.0   | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.11/0.3.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.11/0.3.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.12/0.3.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.12/0.3.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.13/0.3.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.13/0.3.0/jar)        |\n| 0.2.0   | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.11/0.2.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.11/0.2.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.12/0.2.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.12/0.2.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.13/0.2.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.13/0.2.0/jar)        |\n| 0.1.0   | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.11/0.1.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.11/0.1.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.12/0.1.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.12/0.1.0/jar)        | [![Maven Central](https://img.shields.io/maven-central/v/com.cmhteixeira/delegate-macro_2.13/0.1.0)](https://search.maven.org/artifact/com.cmhteixeira/delegate-macro_2.13/0.1.0/jar)        |\n\nImporting the library into your build system (e.g gradle, sbt), is not enough. Before Scala 3, support for macros is a\nbit clunky. You need to follow an extra step.\n\n| Scala 2.11                                                  | Scala 2.12                                                 | Scala 2.13                                                           |\n|-------------------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------------|\n| Import macro paradise plugin  | Import macro paradise plugin | Enable compiler flag `-Ymacro-annotations` required |\n\n### Using macro paradise plugin\n\nLink to macro repo: https://github.com/scalamacros/paradise\n\n#### gradle\n\nAdd the following 3 portions to your build\n\n```gradle\n// build.gradle\n.....\nconfigurations {\n   scalaCompilerPlugin\n}\n\ndependencies {\n  scalaCompilerPlugin \"org.scalamacros:paradise_\u003cyour-scala-version\u003e:\u003cplugin-version\u003e\"\n}\n\ntasks.withType(ScalaCompile) {\n  scalaCompileOptions.additionalParameters = [\n    \"-Xplugin:\" + configurations.scalaCompilerPlugin.asPath\n  ]\n}\n.... \n```\n\nwhere `\u003cyour-scala-version\u003e` must be the full scala version. For example `2.12.13`, and not `2.12`.\n\nIf that doesn't work, google for alternatives.\n\n#### sbt\n\nIt should be quite straightforward.  \nAdd the following line to your build.\n\n```\naddCompilerPlugin(\"org.scalamacros\" % \"paradise_\u003cyour-scala-version\u003e\" % \"\u003cplugin-version\u003e\")\n``` \n\nWhere `\u003cyour-scala-version\u003e` must be the full scala version. For example `2.12.13`, and not `2.12`.\n\nIf that doesn't work, google for alternatives.\n\n### Enabling `-Ymacro-annotations`\n\nIn version `2.13`, the functionality of macro paradise has been included in the scala compiler directly. However, you\nmust still enable the compiler flag `-Ymacro-annotations`.\n\n## IntelliJ IDEA\n\nThere is no IntelliJ support.  \nThis means, regardless of your Scala version, your IDE won't be able to expand the macro. Therefore, it will underline\nyour annotated class with those red squiggly lines, stating your class does not implement all methods of the\ninterface.  \nDon't worry about that. It is aesthetically unpleaseant, but of no real consequence.   \nThe solution would be to develop a public plugin for Intellij for this macro.\n\n![](./documentation/ExampleRedLinesIntellijSupport.png)\n\n## Debug\n\nKnowing what the macro does, either to increase your confidence that it is doing what you meant, or for debugging, you\ncan compile your code in debug mode. This will log what the macro expanded your class into.  \nAchieving this depends on which build system you are using. If using gradle, run `gradlew compileScala -i`. The `-i` is\nfor info. Check more information at the logging section of the gradle documentation.  \nYou can try and force debug mode with `@Delegate(verbose = true)`. However, this might not work if you build system is\nhiding the logs (as is the case for gradle without `-i`).  \nAlternatively, you can use flag `-Ymacro-debug-verbose`. This logs even more detailed information. I believe in this\nscenario everything is dumped to standard output, so it might overcome any logging limitations of your build system.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmhteixeira%2Fdelegate-macro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmhteixeira%2Fdelegate-macro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmhteixeira%2Fdelegate-macro/lists"}