{"id":1326,"date":"2021-10-15T12:00:52","date_gmt":"2021-10-15T10:00:52","guid":{"rendered":"https:\/\/www.loicmathieu.fr\/wordpress\/?p=1326"},"modified":"2023-01-24T12:49:09","modified_gmt":"2023-01-24T11:49:09","slug":"quarkus-tip-selectionner-un-bean-au-runtime","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/quarkus-tip-selectionner-un-bean-au-runtime\/","title":{"rendered":"Quarkus Tip : Select a bean at runtime"},"content":{"rendered":"<p>When developing an application, it is very common to have several implementations of a servicen and to have to select one or the other depending on the environment on which it is deployed.<\/p>\n<p>A classic example: a service that calls an API of an external partner that we want to call only in production, and therefore mock on the development and test \/ UAT \/ staging environments.<\/p>\n<p>Quarkus tries to move to build time, via its Maven or Gradle plugin, the most possible things. Among other things, it discovers CDI beans at build time, and will instantiate only those necessary.<\/p>\n<p>To be able to select a bean, we have the possibility to use the <a title=\"@IfBuildProfile\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#enabling-beans-for-quarkus-build-profile\" target=\"_blank\" rel=\"noopener\"><a>@IfBuildProfile<\/code>code&gt;@IfBuildProfile&lt;\/code<\/a><\/a> annotation, the <a title=\"@IfBuildPropertiy\" href=\"https:\/\/quarkus. io\/guides\/cdi-reference#enabling-beans-for-quarkus-build-properties\" target=\"_blank\" rel=\"noopener\"><a>@IfBuildProperty<\/code>code&gt;@IfBuildProperty&lt;\/code<\/a><\/a>, or <a title=\"CDI alternatives\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#declaring-selected-alternatives\" target=\"_blank\" rel=\"noopener\">CDI alternatives<\/a>. But these solutions will select the bean at build time! This allows to have a different bean for unit tests or dev mode but not once the application has been built. To use this mechanism to select a different bean on a UAT\/staging environment and on the production, you would have to build several packages of the application.<\/p>\n<p>Selecting a bean at runtime is still possible using a CDI <code>Instance<\/code>, it requires a few lines of code.<\/p>\n<p>Here is how to do it.<\/p>\n<p><strong>Step 1<\/strong>: add a property in your <code>application.properties<\/code><\/p>\n<pre>service.implementation-name=mock\n<\/pre>\n<p><strong>Step 2<\/strong>: annotate your two implementations with a CDI qualifier, here we will use <a>@Named<\/code>code&gt;@Named&lt;\/code<\/a> but Quarkus also offers <a>@Identifier<\/code>code&gt;@Identifier&lt;\/code<\/a>.<\/p>\n<pre>@ApplicationScoped\n@Named(\"mock\")\npublic class MockService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<pre>@ApplicationScoped\n@Named(\"real\")\npublic class RealService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<p><strong>Step 3<\/strong>: In the class using your service, select the bean at application startup based on the application configuration.<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {\n    @ConfigProperty(name=\"service.implementation-name\") String implementationName;\n    @Inject Instance remoteServiceInstance;\n\n    private final RemoteService remoteService;\n\n    @PostConstruct\n    void init() {\n        remoteService = remoteServiceInstance\n            .select(NamedLiteral.of(implementationName)).get();\n    }\n\n    \/\/ ...\n}\n<\/pre>\n<p><strong>UPDATE<\/strong> : Martin Kouba (thanks to him) proposed a shorter and clearer implementation, via constructor injection (which, to my great shame, I am not familiar with). So I put below a step 3 with a simplified code:<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {   \n   private RemoteService remoteService;\n\n   MyEndpoint(@ConfigProperty(name=\"service.implementation-name\") String implName, \n         Instance remoteServiceInstance) {\n     remoteService = remoteServiceInstance.select(NamedLiteral.of(implName)).get();\n   }\n\n    \/\/ ...\n}\n<\/pre>\n<p><strong>Caution<\/strong> : the definitions (metadata) of the two beans <code>MockService<\/code> and <code>RemoteService<\/code> will be created and will remain in memory for the life of your application, even if only one of the two will be used. They will not be deleted automatically by Arc, the CDI implementation of Quarkus, via its <a title=\"unused bean deletion\" href=\"https:\/\/quarkus.io\/guides\/cdi-reference#remove_unused_beans\" target=\"_blank\" rel=\"noopener\">unused bean deletion<\/a> mechanism. The beans, on the other hand, if they use a normal scope, will be created in a <a href=\"https:\/\/quarkus.io\/guides\/cdi-reference#lazy_by_default\" target=\"_blank\" rel=\"noopener\">lazy<\/a> manner.<\/p>\n<p>Conclusion: even if selecting a bean at runtime goes against the philosophy of Quarkus, it is very often a necessity and it is possible via a few lines of code. As it is something classic, I will raise the point with the Quarkus community so that we find something more practical, stay tuned ;)<\/p>\n<p><strong>UPDATE<\/strong> : I have since raised the point with the Quarkus community and a more practical solution than using <code>instance.select()<\/code> has been implemented thanks to the <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> and <a>@LookupUnlessProperty<\/code>code&gt;@LookupUnlessProperty&lt;\/code<\/a> annotations that allow to add, for each bean, a condition for their selection based on a configuration property.<\/p>\n<p>So we can replace the previous steps 2 and 3 with these:<\/p>\n<p><strong>Step 2<\/strong>: annotate both your implementations with <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a>.<\/p>\n<pre>@ApplicationScoped\n@LookupIfProperty(name = \"service.implementation-name\", stringValue = \"mock\")\npublic class MockService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<pre>@ApplicationScoped\n@LookupIfProperty(name = \"service.implementation-name\", stringValue = \"real\")\npublic class RealService implements RemoteService {\n    \/\/ ....\n}\n<\/pre>\n<p><strong>Step 3<\/strong>: In the class using your service, the bean must be obtained at startup via the <code>get()<\/code> method of the instance. The presence of the <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> annotation on both implementations will cause only the bean of type <code>MockService<\/code> to be created because the value of the <code>service.implementation-name<\/code> property used in its <a>@LookupIfProperty<\/code>code&gt;@LookupIfProperty&lt;\/code<\/a> instance is <code>mock<\/code>.<\/p>\n<pre>@Path(\"\/api\")\npublic class MyEndpoint {\n    @Inject InstanceremoteServiceInstance;\n\n    private RemoteService remoteService;\n\n    @PostConstruct\n    void init() {\n        remoteService = remoteServiceInstance.get();\n    }\n\n    \/\/ ...\n}\n<\/pre>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>When developing an application, it is very common to have several implementations of a servicen and to have to select one or the other depending on the environment on which it is deployed. A classic example: a service that calls an API of an external partner that we want to call only in production, and therefore mock on the development and test \/ UAT \/ staging environments. Quarkus tries to move to build time, via its Maven or Gradle plugin,&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/quarkus-tip-selectionner-un-bean-au-runtime\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[9],"tags":[198,11,167,199],"class_list":["post-1326","post","type-post","status-publish","format-standard","hentry","category-informatique","tag-cdi","tag-java","tag-quarkus","tag-tips"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1353,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/quarkus-tip-comment-ne-pas-creer-une-extension-quarkus\/","url_meta":{"origin":1326,"position":0},"title":"Quarkus Tip: How NOT to create a Quarkus extension","author":"admin","date":"Tuesday November 16th, 2021","format":false,"excerpt":"When you develop an application composed of several components, it is frequent to want to share some code in an external library, for example via an external JAR integrated as a dependency of your components. Quarkus is an extension framework, each extension it offers allows to integrate a technology (BDD\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1345,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/quarkus-et-les-google-cloud-functions\/","url_meta":{"origin":1326,"position":1},"title":"Quarkus and  the Google Cloud Functions","author":"admin","date":"Tuesday November  2nd, 2021","format":false,"excerpt":"Quarkus is a microservice framework designed for the cloud and the containers. It is designed to have a reduced memory usage and the shortest possible startup time. It is mainly based on standards (Jakarta EE, Eclipse MicroProfile, ...) and allows the use of mature and widespread Java libraries via its\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1440,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/google-cloud-functions-2nd-gen\/","url_meta":{"origin":1326,"position":2},"title":"Google Cloud Functions 2nd gen","author":"admin","date":"Tuesday March 29th, 2022","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen1-instance.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen1-instance.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/cloud-function-gen1-instance.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":923,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/devoxx-france-2019\/","url_meta":{"origin":1326,"position":3},"title":"(Fran\u00e7ais) Devoxx France 2019","author":"admin","date":"Monday May 13th, 2019","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1560,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/quarkus-tip-tester-une-fonction-google-cloud\/","url_meta":{"origin":1326,"position":4},"title":"Quarkus Tip: Testing a Google Cloud function","author":"admin","date":"Thursday December 29th, 2022","format":false,"excerpt":"I recently contributed a PR to Quarkus that contains a testing framework for Google Cloud functions. Quarkus supports creating Google Cloud functions three different ways: Using the Google Cloud API. Using a Quarkus HTTP extension: RESTEasy, Reactive routes, Servlet, Spring Web. Using Funqy, the cloud provider agnostic Quarkus function API.\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1138,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/ma-deuxieme-annee-chez-zenika\/","url_meta":{"origin":1326,"position":5},"title":"(Fran\u00e7ais) Ma deuxi\u00e8me ann\u00e9e chez Zenika","author":"admin","date":"Thursday September  3rd, 2020","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1326","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/comments?post=1326"}],"version-history":[{"count":1,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1326\/revisions"}],"predecessor-version":[{"id":1616,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1326\/revisions\/1616"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/media?parent=1326"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/categories?post=1326"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/tags?post=1326"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}