You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IIInjectionAndScopes.asciidoc 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. ---
  2. title: Injection And Scopes
  3. order: 48
  4. layout: page
  5. ---
  6. [[ii-injection-and-scopes]]
  7. = II - Injection and scopes
  8. In this tutorial we'll take a closer look at the @CDIUI annotation and
  9. use CDI to inject some beans to our application.
  10. [[cdiui]]
  11. @CDIUI
  12. ~~~~~~
  13. The @CDIUI annotation is the way in which you let the Vaadin CDI plugin
  14. know which UI's should be accessible to the user and how they should be
  15. mapped. It accepts one optional String parameter indicating the UI path.
  16. If an explicit path is not provided the class name of the UI will be
  17. used to construct a pathname by the following convention: any trailing
  18. "UI" will be truncated and camelcase will be converted to hyphenated
  19. lowercase. Some examples of the convention:
  20. ....
  21. HelloWorldUI → hello-world
  22. ExampleUI → example
  23. VisualEditor → visual-editor
  24. ....
  25. Passing an empty String as the path will cause the UI to be mapped to
  26. the root of the deployment. Most single UI applications will probably
  27. want to do this.
  28. [[injecting-beans]]
  29. Injecting beans
  30. ~~~~~~~~~~~~~~~
  31. Now that the UI itself has been injected, we can use the @Inject
  32. annotation to further inject beans to it. Let's create something for us
  33. to actually inject.
  34. We'll define the following interface, and an implementation for it.
  35. [source,java]
  36. ....
  37. package com.vaadin.cdi.tutorial;
  38. public interface Greeting {
  39. public String getText();
  40. }
  41. ....
  42. [source,java]
  43. ....
  44. package com.vaadin.cdi.tutorial;
  45. import java.io.Serializable;
  46. public class SimpleGreetingImpl implements Greeting, Serializable {
  47. @Override
  48. public String getText() {
  49. return "Hello, World!";
  50. }
  51. }
  52. ....
  53. So far so good, now we'll inject it into our UI. You'll need to add the
  54. CDI API as a dependency in your pom.xml. (Group id: javax.enterprise,
  55. artefact id: cdi-api, version: 1.2)
  56. [source,java]
  57. ....
  58. package com.vaadin.cdi.tutorial;
  59. import javax.inject.Inject;
  60. import com.vaadin.annotations.Theme;
  61. import com.vaadin.cdi.CDIUI;
  62. import com.vaadin.server.VaadinRequest;
  63. import com.vaadin.ui.Button;
  64. import com.vaadin.ui.Button.ClickEvent;
  65. import com.vaadin.ui.Label;
  66. import com.vaadin.ui.UI;
  67. import com.vaadin.ui.VerticalLayout;
  68. @SuppressWarnings("serial")
  69. @CDIUI("")
  70. @Theme("valo")
  71. public class HelloWorldUI extends UI {
  72. @Inject
  73. private Greeting greeting;
  74. @Override
  75. protected void init(VaadinRequest request) {
  76. final VerticalLayout layout = new VerticalLayout();
  77. layout.setMargin(true);
  78. setContent(layout);
  79. Button button = new Button("Click Me");
  80. button.addClickListener(new Button.ClickListener() {
  81. public void buttonClick(ClickEvent event) {
  82. layout.addComponent(new Label(greeting.getText()));
  83. }
  84. });
  85. layout.addComponent(button);
  86. }
  87. }
  88. ....
  89. Let's run that and see.
  90. image:img/hello-world.png[Injection seems to be working]
  91. So far so good. Suppose we want to say hello to the user by name. We'll
  92. create a class to store our user data in. For now it's a simple POJO
  93. just for storing the name in a single string.
  94. [source,java]
  95. ....
  96. package com.vaadin.cdi.tutorial;
  97. import java.io.Serializable;
  98. public class UserInfo implements Serializable {
  99. private String name;
  100. public UserInfo() {
  101. this.name = "stranger";
  102. }
  103. public UserInfo(String name) {
  104. this.name = name;
  105. }
  106. public String getName() {
  107. return name;
  108. }
  109. public void setName(String name) {
  110. this.name = name;
  111. }
  112. }
  113. ....
  114. We'll inject that to the UI and assign the user some name during
  115. initialization (for now)
  116. [source,java]
  117. ....
  118. @Inject
  119. private UserInfo user;
  120. @Override
  121. protected void init(VaadinRequest request) {
  122. ...
  123. user.setName("Ernest");
  124. }
  125. ....
  126. Then we'll create a new implementation of the Greeting and inject the
  127. user there as well.
  128. [source,java]
  129. ....
  130. package com.vaadin.cdi.tutorial;
  131. import javax.inject.Inject;
  132. public class UserGreetingImpl implements Greeting {
  133. @Inject
  134. private UserInfo user;
  135. @Override
  136. public String getText() {
  137. return "Hello, " + user.getName() + "!";
  138. }
  139. }
  140. ....
  141. Now, it would be easy to think that that's all you need but we're not
  142. quite there. There are two issues with this that need to be addressed.
  143. The first one will become immediately obvious when you try to deploy the
  144. application. The deployment will fail as the injection in HelloWorldUI
  145. is ambiguous, that is CDI doesn't know which implementation of Greeting
  146. we want. +
  147. There are three annotations that are useful in situations like this:
  148. @Default, @Alternative and @Specializes. Giving a bean any of these
  149. annotations will affect it's preference order when the CDI container is
  150. looking for which implementation to inject. Unless otherwise specified,
  151. beans will be considered to have the @Default annotation. Beans with the
  152. @Alternative annotation will only be injected if that particular bean is
  153. named in the beans.xml file (TODO: add link). Beans with the
  154. @Specializes annotation will be considered a drop-in replacement for
  155. it's superclass, and will be used over any implementations it extends. +
  156. In our case, we'll want to give SimpleGreetingImpl the @Default
  157. annotation and UserGreetingImpl the @Alternative annotation.
  158. [source,java]
  159. ....
  160. @Default
  161. public class SimpleGreetingImpl implements Greeting {
  162. ....
  163. [source,java]
  164. ....
  165. @Alternative
  166. public class UserGreetingImpl implements Greeting {
  167. ....
  168. After that the application could actually be deployed. To tell CDI we'll
  169. want to use our alternative implementation we need to create the
  170. beans.xml in our WEB-INF folder, and add the following declaration to
  171. it:
  172. [source,xml]
  173. ....
  174. <beans>
  175. <alternatives>
  176. <class>com.vaadin.cdi.tutorial.UserGreetingImpl</class>
  177. </alternatives>
  178. </beans>
  179. ....
  180. Let's try that out:
  181. image:img/hello-stranger.png[Something's not right]
  182. Better, but not quite there yet. We're getting the wrong username,
  183. despite the fact that we set the username to "Earnest" in the UI. The
  184. problem here is the scope of the bean. If you don't specify a scope for
  185. your bean either in the bean class itself or at the injection point,
  186. it'll default to using the dependent scope. Every time you inject a
  187. dependent bean you'll get a new instance, which is clearly not what we
  188. want here. Let's go back to our UserInfo class and assign it an explicit
  189. scope.
  190. [source,java]
  191. ....
  192. import com.vaadin.cdi.UIScoped;
  193. @UIScoped
  194. public class UserInfo {
  195. ...
  196. ....
  197. The @UIScoped annotation is specific to Vaadin CDI. Anything injected
  198. with that annotation will get the same instance while within the same
  199. UI. Load a different UI and you'll get a different instance. If the
  200. session expires or the UI is closed the instances will be cleaned up. +
  201. Let's see if it worked.
  202. image:img/hello-earnest.png[Something IS right]
  203. Looks like we're making progress.