CDI and Navigation problem

Hi,

I am trying to inject EJBs in a Vaadin applciation and I’m having some difficulties.

I have my main UI class annotated with @CDIUI and some injected beans in it. This is working perfectly.

Then I have a CDIViewProvider injected to my main UI and that is also fine.

Then I have some views annotated with @CDIView and here is my problem. If I inject a EJB (I haven’t tried other regular beans) the object is null. I can inject the same EJB in the main UI and it is fine.

I am sorry if this is a very simple question but I am totally new to CDI.

Thanks in advance.

So to get it straight, you have views with @CDIView which has fields annotated with @Inject, and the CDIViewProvider creates the views for you and navigates to the page. In other words, you never call “new SomeView()” anywhere?

If that is the case then everything should be fine. I have a project set up in the matter. As long as you don’t call “new”, the whole chain should be managed bean. As soon as you do a “new”, the bean isn’t managed anymore and @Inject won’t work. If you for some reason have to call new in some place, you can inside it still restart the chain of managed bean by
asking for the bean from the BeanManager
.

Sorry for not having a clear solution to your issues, but hopefully this provided some info to go on with.

Hi Jens,

thanks a lot for the answer!

Unfortunately I haven’t managed to get this working.

Yes, I am definitely not calling new anywhere! I am sure I am making a really stupid error but I can’t find a way to fix it.

I will add some more code in case you see something really wrong:

@CDIUI
public class MainUI extends UI {

    @Inject
    MyEJB myEJB; // this gets injected properly
     
    @Inject
    CDIViewProvider navigatorViewProvider;

    private Navigator navigator;

    private SingleComponentContainer viewContainer;

    ....

    protected void init(VaadinRequest request) {

        viewContainer = new Panel();

        navigator = new Navigator(this, viewContainer);
        navigator.addProvider(navigatorViewProvider);

...

[/code][code]

@CDIView
public class MyCDIView extends VerticalLayout implements View{

    @Inject
    MyEJB myEJB; // this doesn't work!

    public MyCDIView () {
         // myEJB is null at this point
...

Taking a look at the log:

  • Attempting to retrieve view name from string “”
  • Looking for view with name “”
  • com.package.MyCDIView is annotated, the viewName is “”
  • Bean Managed Bean [class com.package.MyCDIView]
    with qualifiers [@Any @Default]
    with viewName “” is one alternative
  • … (same for the rest of the CDIViews)

I just realized this block of logs is repeated twice, like it is scaning for views twice. Shouldn’t this happen only once?

Thanks a lot for your help again!
Francesco

Ok,

I started debugging the CDIViewProvider from the Vaadin CDI addon and found something in line 213.

The method is getView(String viewName)

There is one line that throws an exception but it is not captured or displayed nowhere:

View view = (View) beanManager.getReference(viewBean,
                    viewBean.getBeanClass(), currentViewCreationalContext);
LOG().log(Level.INFO, "Returning view instance {0}", view);
return view;

The call to that method fails. It never gets to the log part or the return statement.

Any ideas why this could happen? the objects viewBean and currentViewCreationalContext look good (or are not null at least) but I can’t really tell!

Thanks :slight_smile:

Ok!

I discovered that moving the initialization code from the Constructor to the method:
public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent)
solved the problem.

I am sure this is due to my lack of understanting of CDI. So beans are not injected in the constructor? When can I trust a bean is injected?

Thanks and sorry if this is too basic but I couldn’t find too many references for this…

See e.g.
this page
. Injections are effectively performed after your constructor code is executed, so you should never rely on them having been performed in the code in your constructor. For the detailed reasons, you might need to dive deeper into how CDI is implemented and into Java Language Specification on how constructors and field initialization actually work in Java (which does hold some surprises to many users).

Use methods annotated with @PostConstruct instead, or check them even later such as in your case when entering the view.

It is true that this aspect of CDI is not very clearly documented in most places, including tutorials on CDI.

Thanks a lot to both of you! You are really helpful! :slight_smile:

How did you finally solve the problem, injecting MyEJB into the MyCDIView? Please give simple code.

It could save some time for beginners.

You can try adding it to init() method. The bean class is initialized first.

@Inject
MyEJB myEJB;

protected void init() {
myEJB.getClass();
}

public MyCDIView () {
System.out.println(myEJB.toString());
}

Have you tried constructor injection? It works fine for me:


@CDIView
 public class MyCDIView extends VerticalLayout implements View{
 
     private MyEJB myEJB;
 
     @Inject
     public MyCDIView (MyEJB myEJB) {
          this.myEJB = myEJB;
          // Rest of the stuff
     }

I can not make my inject work on view even though it worked perfectly on UI. I need some help, please.

I have the service like that:

@Local public interface MediaManagerService { [code]
@Stateless
public class MediaManagerServiceImpl implements MediaManagerService, Serializable {

private static final long serialVersionUID = -3484115607954217804L;

@PersistenceContext(name="MediaManagerPersistenceUnit", 
                    unitName="MediaManagerPersistenceUnit")
private EntityManager _em;

[/code]I can inject service successful in UI by this code:

[code]
@CDIUI
public class MainUI extends ManagedUI {
private Navigator _navigator;

@Inject
private CDIViewProvider _viewProvider;

@Inject
private MediaManagerService _service;

[/code]But in the view, it always throws null.

[code]
@CDIView(“MovieView”)
public class MovieView extends ManagedComponent implements View {
public static final String NAME = “MovieView”;

@Inject
private MediaManagerService _service;

[/code]The _service always throws null in the View.
This is from the console:

Bean Managed Bean [class com.tien113.ui.MovieView] with qualifiers [@Any @Default] with viewName "MovieView" is one alternative Can anyone help me, please…

don’t put @Inject bean in constructor, it will be null.