{"id":17257556,"url":"https://github.com/hjohn/dirk","last_synced_at":"2025-07-31T22:12:56.579Z","repository":{"id":8552683,"uuid":"10176209","full_name":"hjohn/Dirk","owner":"hjohn","description":"Dirk DI, a light-weight DI framework which can have its dependencies changed at runtime","archived":false,"fork":false,"pushed_at":"2022-07-02T10:47:04.000Z","size":1906,"stargazers_count":31,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T19:52:04.801Z","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":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hjohn.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-05-20T15:51:28.000Z","updated_at":"2024-12-14T13:58:36.000Z","dependencies_parsed_at":"2022-09-16T13:47:03.638Z","dependency_job_id":null,"html_url":"https://github.com/hjohn/Dirk","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FDirk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FDirk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FDirk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FDirk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hjohn","download_url":"https://codeload.github.com/hjohn/Dirk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248826802,"owners_count":21167751,"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":"2024-10-15T07:17:50.558Z","updated_at":"2025-04-14T05:32:16.792Z","avatar_url":"https://github.com/hjohn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dirk DI\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.int4.dirk/dirk-di/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.int4.dirk/dirk-di)\n[![Build Status](https://github.com/hjohn/hs.ddif/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/hjohn/hs.ddif/actions)\n[![Coverage](https://codecov.io/gh/hjohn/Dirk/branch/master/graph/badge.svg?token=QCNNRFYF98)](https://codecov.io/gh/hjohn/Dirk)\n[![License](https://img.shields.io/badge/License-BSD_2--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)\n[![javadoc](https://javadoc.io/badge2/org.int4.dirk/parent/javadoc.svg)](https://javadoc.io/doc/org.int4.dirk/parent)\n\nDirk is a small, highly customizable, dynamic dependency injection framework.\n\n## Quick Start\n\nAdd a dependency to Dirk in your POM:\n\n    \u003cgroupId\u003eorg.int4.dirk\u003c/groupId\u003e\n    \u003cartifactId\u003edirk-di\u003cartifactId\u003e\n    \u003cversion\u003e1.0.0-beta1\u003c/version\u003e\n\nAssume there is a small class which depends on a `String` which Dirk should provide:\n\n    public class Greeter {\n        @Inject private String greeting;\n\n        public void greet() {\n            System.out.println(greeting);\n        }\n    }\n\nCreate an injector:\n\n    Injector injector = Injectors.autoDiscovering();\n\nRegister a `String` and the `Greeter` class:\n\n    injector.registerInstance(\"Hello World\");\n    injector.register(Greeter.class);\n\nLet the injector create an instance of `Greeter`, then call its `greet` method and observe that the\ninjected greeting is printed to the console:\n\n    Greeter greeter = injector.getInstance(Greeter.class);\n\n    greeter.greet();  // prints \"Hello World\"\n\n## Features\n\n- Dependency Injection\n  - Constructor, Method and Field injection\n  - Supports qualifiers, scopes, generics and lifecycle callbacks\n- Dynamic\n  - Register and unregister types at any time\n  - Ensures all dependencies are always resolvable and unambiguous\n- Highly Customizable\n  - Choose what annotations and extensions Dirk should use\n  - Built-in styles for Jakarta (CDI), JSR-330 and Dirk DI or create a new one\n- Extendable\n  - Fully documented API and SPI\n  - Common DI features are just extensions in Dirk\n- Small\n  - Core jar and its dependencies are around 200 kB\n\nSeveral well known features of DI systems are implemented as standard extensions to Dirk's core system. Included\nare extensions to support:\n\n- Producer methods and fields\n- Delayed lookup of dependencies (providers)\n- Assisted Injection\n- Proxy creation and injection\n- List, Set and Optional injection\n\n# Available Dependency Injection Styles\n\n| |Dirk|CDI|Jakarta|JSR-330|\n|---|---|---|---|---|\n|Artifact|dirk-di|dirk-cdi|dirk-jakarta|dirk-jsr330|\n|Standard Annotations|`jakarta.inject`|`jakarta.inject`|`jakarta.inject`|`javax.inject`|\n|Additional Annotations|`org.int4.dirk.annotations`|`jakarta.enterprise.inject`|`org.int4.dirk.annotations`|`org.int4.dirk.annotations`|\n|Default Annotation|`@Default`|`@Default`|-|-|\n|Any Annotation|`@Any`|`@Any`|-|-|\n|Optional Injection|`@Opt`|-|`@Opt`|`@Opt`|\n|Producer Support|`@Produces`|`@Produces`|`@Produces`|`@Produces`|\n|Assisted Injection|`@Assisted` \u0026 `@Argument`\u003csup\u003e1\u003c/sup\u003e|-|`@Assisted` \u0026 `@Argument`\u003csup\u003e1\u003c/sup\u003e|`@Assisted` \u0026 `@Argument`\u003csup\u003e1\u003c/sup\u003e|\n|Indirect Injection|`Provider`|`Provider` \u0026 `Instance`|`Provider`|`Provider`|\n|Collection Injection|`List` \u0026 `Set`|-|`List` \u0026 `Set`|`List` \u0026 `Set`|\n|Proxy Support|Yes\u003csup\u003e2\u003c/sup\u003e|Yes\u003csup\u003e2\u003c/sup\u003e|Yes\u003csup\u003e2\u003c/sup\u003e|Yes\u003csup\u003e2\u003c/sup\u003e|\n\n\u003csup\u003e1\u003c/sup\u003e When detected on classpath by including `org.int4.dirk.extensions:extensions-assisted`  \n\u003csup\u003e2\u003c/sup\u003e When detected on classpath by including `org.int4.dirk.extensions:extensions-proxy`\n\n# Documentation\n\n## Terminology\n\n|Term|Explanation|\n|---|---|\n|Candidate|A qualified type that could be used to satisfy a dependency|\n|Dependency|A qualified type required by an inject annotated constructor, method or field|\n\n## Dependency Injection\n\nDependencies are other classes or types that are required for the correct functioning of a class. A\ndependency can be a class, an interface, a generic type or a primitive type. Dependency injection supplies \nthese required values automatically. Dependencies can be supplied through constructor or method parameters or\nby setting fields directly. \n\nConstructor injection:\n\n    public class Greeter {\n        @Inject\n        public Greeter(String greeting) { ... }\n    }\n\nMethod injection:\n\n    public class Greeter {\n        @Inject\n        void setGreeting(String greeting) { ... }\n    }\n\nField injection:\n\n    public class Greeter {\n        @Inject \n        private String greeting;\n    }\n\nAny of the above forms can have a `String` dependency injected. Note that when using method or field injection\nthe values are set *after* the constructor is called. Referring to these values in the constructor therefore could\nresult in an error, instead consider implementing this logic in an initializer method that can be called after \ninjection completes. See Lifecycle Callbacks for more information.\n\n### Type Resolution\n\nWhen considering the type to inject for a dependency, the system follows standard Java rules when doing\ntype conversions. Any type conversion which does not require a cast is allowed, except primitive widening \nconversions. This includes boxing and unboxing conversions and compatible generic conversions. \n\nWhen a class is registered with an injector it can satisfy one or more types. The types that can\nbe satisfied are all implemented interfaces, its super classes and any interfaces and super classes these\nimplement or extend in turn. The `Greeter` class for example could be a candidate for dependencies of type \n`Greeter` and `Object`. \n\nThe framework also does automatic boxing and unboxing conversion. For primitive types and their boxed types\nthis adds another possible type they can supply. An `Integer` can be used to inject an `int` or vice versa.\nOther types the `Integer` class could satisfy are `Number` (its super class), `Object` (`Number`'s\nsuper class), `Comparable\u003cInteger\u003e` (implemented interface) and `Serializable` (interface implemented by \n`Number`).\n\nExample:\n\n    injector.registerInstance(42);  // register an int with value 42\n\nWould satisfy all the following dependencies:\n\n    @Inject int i;\n    @Inject Integer integer;\n    @Inject Number number;\n    @Inject Object object;\n    @Inject Comparable\u003cInteger\u003e integerComparable;\n    @Inject Comparable\u003c? extends Number\u003e numberComparable;\n\n... but would not satisfy:\n\n    @Inject long l;  // Primitive widening conversion not allowed\n    @Inject Long longValue;  // Integer cannot be cast to Long\n    @Inject Comparable\u003cNumber\u003e comparable;  // Incompatible generic type\n\n### Qualifiers\n\nTypes registered with the injector can be annotated with qualifier annotations. These annotations provide\nanother way to distinguish candidates besides their types. This makes it possible to distinguish between multiple\ncandidates that may all match a dependency where exactly one dependency is required. Qualifiers can be placed on \ncandidates and on dependencies. In order for a candidate to match, it must have all the qualifiers specified on \nthe dependency.\n\nA dependency with an `@English` qualifier annotation:\n\n    @Inject @English private String greeting;\n\nOr as a constructor or method parameter:\n\n    public Greeter(@English String greeting) { ... }\n    public void setGreeting(@English String greeting) { ... }\n\nCandidates can be annotated directly with qualifiers, or they can be specified during\nregistration (for instances).\n\nA `Greeter` candidate with an `@English` qualifier annotation:\n\n    @English\n    public class Greeter { ... }\n\nRegistering `String` candidate instances with different qualifiers:\n\n    injector.registerInstance(\"Hello World\", English.class);\n    injector.registerInstance(\"Hallo Wereld\", Dutch.class);\n\nAs an example, given two `String` candidates, one annotated with `@Greeting` and `@English`, the other\nannotated with `@Greeting` and `@Dutch`:\n\n    injector.registerInstance(\"Hello World\", English.class, Greeting.class);\n    injector.registerInstance(\"Hallo Wereld\", Dutch.class, Greeting.class);\n\nThen the following dependencies could be satisfied:\n\n    @Greeting @English String s;  // an English greeting\n    @Greeting @Dutch String s;    // a Dutch greeting\n    @English String s;            // any English String\n    @Dutch String s;              // any Dutch String\n    \nThe following dependencies will not be satisfied:\n\n    @Greeting String s;          // ambiguous, English or Dutch greeting?\n    String s;                    // ambiguous, there are two String candidates\n    @Greeting @French String s;  // unsatisfiable, no French greeting was registered\n    @English int englishNumber;  // unsatisfiable, no int was registered\n\n### Scopes\n\nScopes are used to control the lifecycle of candidates, and which instance of a candidate is used to satisfy a\ndependency. The injector supports two types of scopes, pseudo-scopes and normal scopes. Candidates which have a \npseudo-scope are never wrapped in a proxy, and do not need to use indirection to resolve scope conflicts. Candidates \nwith a normal scope will require a proxy (or indirection via a provider) when injected into other candidates with a \ndifferent scope.\n\nWhich scopes are considered pseudo-scopes and which scopes provide the mandatory singleton and unscoped scopes is \ndetermined by the used `ScopeStrategy`. The actual implementation of each scope is provided by a corresponding\n`ScopeResolver` when creating the injector.\n\n### Lifecycle\n\nWhen the injector is configured to do lifecycle callbacks (for example, calling  `@PostConstruct` or `@PreDestroy`\nannotated methods), the injector will call these, respectively, after injection completes and just before the candidate\nis removed.\n\n## Dependency validation during registration\n\nWhen adding or removing candidates from the injector, the injector ensures that all (remaining) registered \ncandidates can have their dependencies satisfied. If the addition or removal would result in unsatisfied or\nambiguous dependencies then an exception is thrown explaining the problem and the addition or removal is rolled back\nto the previous consistent state.\n\nThe injector can throw the following exceptions to indicate a problem during addition or removal:\n\n- `AmbiguousDependencyException` when a new candidate was added which requires a single candidate for a dependency\nbut multiple candidates are available\n- `UnsatisfiedDependencyException` when a new candidate was added which requires a single candidate for a dependency\nbut no candidates were available\n- `AmbiguousRequiredDependencyException` when the addition or removal of a candidate would cause another dependency in\nanother candidate to become ambiguous, for example when a new candidate supplies another option for a dependency that \nwas already satisfied\n- `UnsatisfiedRequiredDependencyException` when the addition or removal of a candidate would cause another dependency \nin another candidate to become unsatisfied, for example when a removed candidate was the only supplier of a dependency\n- `CyclicDependencyException` when a dependency cycle was detected amongst two or more candidates that was not broken\nby making use of a provider\n- `ScopeConflictException` when a scoped dependency depends directly on another scoped dependency, and the conflict\ncould not be resolved automatically by means of a proxy\n  \n## Registration of Candidates at runtime\n\nDirk allows addition and removal of new candidates at any time, assuming the change won't leave the injector in an\ninconsistent state where it can't satisfy all its existing dependencies.\n\nLet's assume there is a class which requires a list of books:\n\n    class BookShop {\n        @Inject List\u003cBook\u003e availableBooks;\n\n        List\u003cBook\u003e getBooks() { return availableBooks; }\n    }\n\nThe class is registered, and an instance is obtained:\n\n    injector.register(BookShop.class);\n    \n    BookShop bookShop = injector.getInstance(BookShop.class);\n\nWhen calling `getBooks` the list will be empty as no candidates were registered that supply a type `Book`:\n\n    assertThat(bookShop.getBooks()).isEmpty();  // passes\n\nThis can be resolved by registering a `Book` and obtaining a new `BookShop` instance:\n\n    injector.registerInstance(new Book(\"Dune\"));\n\n    BookShop bookShop2 = injector.getInstance(BookShop.class);\n\n    assertThat(bookShop2.getBooks()).hasSize(1);  // passes\n\nCreating a new `BookShop` every time the list of available books changes is a bit cumbersome, so it is possible to \nuse indirection to obtain the latest available books by means of a provider. Redefine the `BookShop` class:\n\n    class ModifiedBookShop {\n        @Inject Provider\u003cList\u003cBook\u003e\u003e availableBooks;\n\n        List\u003cBook\u003e getBooks() { return availableBooks.get(); }\n    }\n\nAn instance of this class will now immediately respond to a change in the books available:\n\n    injector.register(ModifiedBookShop.class);\n    \n    ModifiedBookShop modifiedBookShop = injector.getInstance(ModifiedBookShop.class);\n\n    assertThat(modifiedBookShop.getBooks()).isEmpty();  // passes\n\n    injector.registerInstance(new Book(\"Dune\"));\n\n    assertThat(modifiedBookShop.getBooks()).hasSize(1);  // passes\n\nIn more complex scenario's it is sometimes necessary to register multiple candidates simultaneously to avoid a chicken/egg\ntype problem. Given two classes:\n\n    class A {\n        @Inject B b;  // depends on B\n    }\n\n    class B {\n        @Inject Provider\u003cA\u003e a;  // indirectly depends on A\n    }\n    \nRegistering either of these two candidates separately is not allowed as not all dependencies could be satisfied:\n\n    injector.register(A.class);  // --\u003e UnsatisfiedDependencyException, requires B\n    injector.register(B.class);  // --\u003e UnsatisfiedDependencyException, requires A\n\nHowever, registering both at the same time works as expected:\n\n    injector.register(List.of(A.class, B.class));  // works!\n\n## Auto Discovery\n\nWhen auto discovery is enabled, Dirk will attempt to automatically register candidates referred to in dependencies\nthat are not yet registered, assuming it can find a way to construct them. Given two classes:\n\n    class BookShop {\n        @Inject CreditCardPaymentProcessor paymentProcessor;\n    }\n\n    public class CreditCardPaymentProcessor {\n    }\n\nIn order to create a `BookShop` instance, normally a `CreditCardPaymentProcessor` must be registered first (or simultaneously):\n\n    Injector injector = Injectors.manual();\n\n    injector.register(CreditCardPaymentProcessor.class);\n    injector.register(BookShop.class);\n\n    BookShop bookShop = injector.getInstance(BookShop.class);\n\nSince `CreditCardPaymentProcessor` has an empty public constructor, the candidate could be automatically discovered when\nDirk encounters the missing dependency in `BookShop`:\n\n    Injector injector = Injectors.autoDiscovering();\n\n    injector.register(BookShop.class);  // registers BookShop and the discovered type CreditCardPaymentProcessor\n\n    BookShop bookShop = injector.getInstance(BookShop.class);\n\nThis automatic discovery works recursively and so large graphs of dependent candidates can all be discovered by \nregistering only a few root candidates.\n\n## Optional Injection\n\nDirk allows dependencies to be optional if configured as such. When a dependency is optional, and no suitable candidate\nis available, Dirk will either inject `null` (for constructor and method parameters) or skip injection completely (for \nfield injection). For example:\n\n    class Greeter {\n        @Inject @Opt private String greeting = \"Hello World\";\n    }\n\nWhen no `String` candidate is available, this version of the `Greeter` class will fall back to a default greeting.\nUsing constructor injection the same can be achieved as follows:\n\n    class Greeter {\n        final String greeting;\n\n        @Inject\n        Greeter(@Opt String greeting) {\n            this.greeting = greeting == null ? \"Hello World\" : greeting;    \n        }\n    }\n\nThis allows a convenient way to have default values for, for example, configuration settings:\n\n    class TimeProvider {\n        @Inject @Opt @Named(\"server.ntp.url\") String url = \"pool.ntp.org\";\n        @Inject @Opt @Named(\"server.sync.interval\") int interval = 3600;  // every hour\n    }\n\n## Customizing Injectors\n\nThe injector can be customized in several ways:\n\n- The `InjectorStrategy` allows for detailed customization of how the injector works:\n  - `AnnotationStrategy` is responsible for detecting injectable members and their qualifiers\n  - `ScopeStrategy` is responsible for detecting scope annotations, and configuring default scope annotations\n  - `ProxyStrategy` is responsible for creating proxies\n  - `LifeCycleCallbacksFactory` controls which and in what order lifecycle methods are to be called\n- Using `InjectionTargetExtension`s\n  - Allows customizing injection targets of a specific generic interface type\n    - Inject lists of instances using the `ListInjectionTargetExtension`\n    - Inject sets of instances using the `SetInjectionTargetExtension`\n    - Inject providers to allow runtime creation of instances using the `ProviderInjectionTargetExtension`\n    - Inject CDI `Instance` types using the `InstanceInjectionTargetExtension`\n- Using `TypeRegistrationExtension`s\n  - Allows detecting additional candidates when a type is registered\n    - Add additional candidates for each `@Produces` annotation using the `ProducesTypeRegistrationExtension`\n    - Add a candidate when types implement the `Provider` interface\n    - Assisted injection: When registering a SAM type (a class or interface with a single abstract method) automatically generate\n      an implementation of this method which produces a new candidate, see `AssistedTypeRegistrationExtension`\n- Using `ScopeResolver`s\n  - Allows creating resolvers for custom scope annotations \n- The injector can be configured to only provide candidates explicitly registered with it or also allow auto \n  discovery of additional candidates through their dependencies\n\n## Extensions\n\n### Type Registration Extensions\n\nA `TypeRegistrationExtension` is called whenever a new type is encountered by the injector during registration.\nThe extension is given the opportunity to register additional types that it can derive from the new type. Usually,\nadditional types are derived by inspecting the given type for annotations or interfaces it implements.\n\n### Injection Target Extension\n\nAn `InjectionTargetExtension` allows creating instances of a specific generic interface prior to injection.\nThe interface must have at least one type variable which the extension must expose to the injector as its element \ntype. The element type, together with any qualifiers on the injection target, determines which candidates can be \nused by the extension to provide the interface implementation. The extension is allowed to delay the lookup or\nperform it immediately. \n\nInterfaces which are extended by an injection target extension can no longer be directly injected, even if a\ncandidate implements the interface.\n\nExamples are the `ListInjectionTargetExtension` and the `ProviderInjectionTargetExtension`, which provide support for\ninjecting lists of candidates or delayed lookup of candidates (through the `List` and `Provider` interfaces)\nrespectively.\n\nExtensions which do delayed lookup are allowed to wrap any other extended type, but in all other cases extensions \ncannot be nested.\n\n# The Core Library\n\nDirk's library and extension modules provide several standard extensions, strategies and scope resolvers that are \nnormally integrated directly in most dependency injection frameworks. These are maintained as part of the project\nand can be used as desired, or serve as a starting point for 3rd party customizations.\n\n## Injection Target Extensions\n\n- `ListInjectionTargetExtension` supports injecting multiple matching candidates as instances in a `List`.\n- `SetInjectionTargetExtension` supports injecting multiple matching candidates as instances in a `Set`.\n- `ProviderInjectionTargetExtension` supports indirect access to candidate instances using a\n  configurable interface (often the `Provider` interface)\n  \n## Type Registration Extensions\n\n### `ProducesTypeRegistrationExtension`\n\nAllows fields and methods to act as factories for additional candidates using a configurable producer annotation.\nProducer methods with parameters are considered to offer candidates with dependencies which are to be provided when the\nmethod is called.\n\nThe following examples assume the annotation `@Produces` is configured to mark producer fields and methods:\n\nA field which produces a `String`:\n\n    @Produces String greeting = \"Hello World\";\n\nA method which produces a `Connection` given a URI:\n\n    @Produces Connection createConnection(URI uri) { ... }\n\nProducers can be static or non-static. Static producers can be called at any time and have no access to any\ndependencies injected in their owner instance. Non-static producers can either have dependencies provided as parameters\n(in the case of a producer method) or by accessing fields in their owner instance.\n\n### `ProviderTypeRegistrationExtension`\n\nAllows a type to act as a factory for an additional candidate when it implements a configurable interface (typically, \nthe `Provider` interface).\n\nBelow an example of a class that implements the `Provider` interface and provides an additional candidate `Connection`:\n\n    class ConnectionProvider implements Provider\u003cConnection\u003e {\n        @Inject URI uri;\n\n        @Override\n        public Connection get() { ... }\n    }\n\n### `AssistedTypeRegistrationExtension`\n\nAllows a type which has a single abstract method (a SAM type) with a non-void return type to act as a factory for the \nreturned type; any dependencies the produced type may have are injected by the injector, including the arguments \nsupplied to the factory method; this is otherwise known as assisted injection.\n\nAssume we have a candidate that requires an additional parameter at runtime before it can be constructed, but also\nhas a required dependency:\n\n    class Greeter {\n        @Inject String greeting;  // a normal dependency\n        @Inject @Argument LocalTime timeOfDay;\n\n        void greet() { ... }\n    }\n\nWith this extension we can have Dirk generate a factory that can be injected, and which takes the additional argument\nas a parameter:\n\n    @Inject Function\u003cLocalTime, Greeter\u003e greeterFactory;\n\nThe factory can be called as a normal `Function`:\n\n    Greeter greeter = greeterFactory.apply(LocalTime.now());\n \n    greeter.greet();\n\nAny SAM type can be used, as long as the arguments its method accepts can be matched up with the arguments in the \nproduced type. The following two examples would also allow constructing the `Greeter` type:\n\n    interface GreeterFactory {\n        Greeter createGreeter(LocalTime timeOfDay);\n    }\n\n... and:\n\n    abstract class GreeterFactory {\n        Greeter createGreeter(LocalTime timeOfDay);\n    }\n\nImportant note: in order for Dirk to match up the argument names, classes should be compiled with parameter name\ninformation (use the `-parameters` flag for `javac`). Alternatively, the names can be explicitly specified with the \n`@Argument` annotation:\n\n    abstract class GreeterFactory {\n        Greeter createGreeter(@Argument(\"timeOfDay\") LocalTime timeOfDay);\n    }\n\n# BSD License\n\nCopyright (c) 2013-2022, John Hendrikx\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n# Dependencies and Acknowledgments\n\n### Reflections\n\nLicense: WTFPL (http://www.wtfpl.net/)  \nhttps://github.com/ronmamo/reflections\n\nLinking: Maven Dependency\n\nUsed for:\n- Scanning classpath for annotations\n\n### Geantyref\n\nLicense: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)   \nhttps://github.com/leangen/geantyref\n\nLinking: Maven Dependency\n\nUsed for:\n- Implementation of Annotation interface\n\n### Apache Commons Lang\n\nLicense: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)  \nhttps://commons.apache.org/proper/commons-lang/   \n\nLinking: Embedded (minimal required code directly included)\n\nUsed for:\n- `TypeUtils` for dealing with generic types and type variables\n\n### Byte Buddy\n\nLicense: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)  \nhttps://bytebuddy.net/\n\nLinking: Maven Dependency (optional)\n\nUsed for:\n- Generating factories for Assisted Injection\n- Generating proxies\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjohn%2Fdirk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhjohn%2Fdirk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjohn%2Fdirk/lists"}