@PostConstruct not working

I am using vaadin 8.

I have the following class:

package org.app.ui.masterdetail.views;

import javax.annotation.PostConstruct;
import javax.inject.Inject

@CDIView("")
public class TitleView extends VerticalLayout implements View {
	
	@Inject
	TitleService service;
	
	public TitleView() {
		Label label01 = new Label("Title01");
		addComponent(label01);		
	}
	
    @PostConstruct
    void init() {
		Label label02 = new Label("Title02");
		addComponent(label02);
		
		Label label03 = new Label(service.getTitle(2).getTitle());
		addComponent(label03);
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
    }
}

I get only shown “Title01”.

I get not “Title02” and the result of label02.

What make i wrong?

TiteService is a EJB which stores the Title.

Hi,

maybe a silly question: are you using CDIViewProvider with your Navigator?

HTH
Marco

No

I navigate to the View with .addCompnent(new TitleView())

@SuppressWarnings("serial")
@CDIView("")
public class MasterDetailView extends VerticalLayout implements View {

	private MainMenu mainMenu;

	private HorizontalLayout allView;
	private CssLayout menuView;
	private CssLayout contentView;
	private Button title;

	public MasterDetailView() {
		mainMenu = new MainMenu();
		allView = new HorizontalLayout();
		menuView = new CssLayout();
		menuView.addStyleName(ValoTheme.MENU_ROOT);
		
		contentView = new CssLayout();

		menuView.addComponent(head);
		menuView.addComponent(showTitleView());

		allView.addComponent(menuView);
		allView.addComponent(contentView);
		allView.setSizeFull();

		addComponent(mainMenu);
		addComponent(allView);
	}

	private Button showTitleView() {
		title = new Button("Title", new Button.ClickListener() {
			@Override
			public void buttonClick(ClickEvent event) {
				contentView.removeAllComponents();
				contentView.addComponent(new TitleView());
			}
		});
		return title;
	}

}

In the Class MainMenu i use a normal Navigator to navigate to MasterDetailView.

In MasterViewDetail i have a another Navigation with addComponent, because the Container where to show the view is here different.

On the end i send the code of the MainMeu for understanding.

package org.app.ui.masterdetail.views;

@CDIView("")
public class TitleView extends VerticalLayout implements View {

	@Inject
	TitleService service;

	public TitleView() {
		Label label01 = new Label("List1 of Title");
		addComponent(label01);
	}

	@PostConstruct
	void init() {
		Label label02 = new Label("List2 of Title");
		addComponent(label02);

		Label label03 = new Label(service.getTitle(2).getTitle());
		addComponent(label03);
	}

	@Override
	public void enter(ViewChangeListener.ViewChangeEvent event) {
	}
}

Code of MainMeu for understanding:

package org.app.ui;

@PushStateNavigation
public class MainMenu extends CustomComponent {

	public MainMenu() {
		HorizontalLayout layout = new HorizontalLayout();
		layout.addComponent(personViewButton);
		layout.addComponent(masterDetailViewButton);
		layout.addComponent(helpViewButton);
		layout.setSizeUndefined();
		layout.setSpacing(true);
		setSizeUndefined();
		setCompositionRoot(layout);
	}
	
	
	Button personViewButton = new Button(MainView.PERSON_VIEW,
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.PERSON_VIEW));
		
	Button masterDetailViewButton = new Button("Master Detail",
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.MASTER_DETAIL_VIEW));
		
	Button helpViewButton = new Button(MainView.HELP_VIEW,
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.HELP_VIEW));
		
	private String getLogoutPath() {
		return getUI().getPage().getLocation().getPath();
	}
}

If you manually create a new TitleView instances they will not be managed by the DI container so @Inject and @PostConstruct won’t work.

how can i solve it then?

How can i create in my case a new TitleView instance?

From the code you posted I would suggest you to

  • inject CDIViewProvider in your UI and add it to Navigator, so you don’t need to manually add views annotated with @CIDView and their dependecies will be injected by DI container
  • Remove @CDIView annotation from TitleView since it seems to me to be a component rather than a view
  • Add to TitleView a constructor that takes TitleService as input parameter and remove @Inject from field
  • Inject TitleService into MasterDetailView and on the button listener do new TitleView(titleService)

There are other ways to do it but I have no clear the structure of your app

HTH
Marco

As a side note @PushStateNavigation must be put on UI class

Sorry when i must come again.
But it still not works.

I try to explain you what is my problem.

I am using Java EE7 + Wildfly 11 + Vaadin 8.
All should be managed by the DI Container.
I want to design a Application like in the picture attached.
My Problem is to realize the navigation in Part 2.

In “Part 1” I managed my Navigation so:
When i click the Button Address then all Addresses from the database are shown in the Content01View-Area.
When i click the Button Help then Help-Text is shown in the Content01View-Area.
All goes well.
I use the Source-Code of the following 2 classes:

package org.app.ui;

@CDIUI("")
@PushStateNavigation
public class MainView extends UI {

	@Inject
    CDIViewProvider viewProvider;
	
	private Navigator navigator;

	public static final String PERSON_VIEW = "Person";
	public static final String MASTER_DETAIL_VIEW = "MasterDetail";
	public static final String HELP_VIEW = "Help";

	@Override
	protected void init(VaadinRequest request) {
		final VerticalLayout mainLayout = new VerticalLayout();
		final CssLayout menuView = new CssLayout();
		final CssLayout content01View = new CssLayout();

		mainLayout.addComponent(menuView);
		mainLayout.addComponent(content01View);
		mainLayout.setMargin(true);
		mainLayout.setSpacing(true);
		setContent(mainLayout);

		navigator = new Navigator(this, content01View);
		navigator.addView("", new LoginView());
		navigator.addView(PERSON_VIEW, new PersonView());
		navigator.addView(MASTER_DETAIL_VIEW, new MasterDetailView());
		navigator.addView(HELP_VIEW, new HelpView());
	}
}
package org.app.ui;

@PushStateNavigation
public class TopMenu extends CustomComponent {

	public TopMenu() {
		HorizontalLayout layout = new HorizontalLayout();
		layout.addComponent(personViewButton);
		layout.addComponent(masterDetailViewButton);
		layout.addComponent(helpViewButton);
		
		layout.addComponent(logoutButton());
		layout.setSizeUndefined();
		layout.setSpacing(true);
		setSizeUndefined();
		setCompositionRoot(layout);
	}
	Button personViewButton = new Button(MainView.PERSON_VIEW,
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.PERSON_VIEW));
	Button masterDetailViewButton = new Button("Master Detail",
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.MASTER_DETAIL_VIEW));
	Button helpViewButton = new Button(MainView.HELP_VIEW,
			e -> UI.getCurrent().getNavigator().navigateTo(MainView.HELP_VIEW));
}

I navigate now in Part 1 to MasterDetailView. This works fine.

I get Problems now to navigate in Part 2, when i want to navigate in the MasterDetailView to the TitleView.

package org.app.ui.masterdetail;

@SuppressWarnings("serial")
@CDIView("")
public class MasterDetailView extends VerticalLayout implements View {

	@Inject
	TitleService service;
	
	private TopMenu topMenu;
	private HorizontalLayout allView;
	private CssLayout leftMenu;
	private CssLayout content02View;
	private Button title;

	public MasterDetailView() {
		topMenu = new TopMenu();
		allView = new HorizontalLayout();
		leftMenu = new CssLayout();
		leftMenu.addStyleName(ValoTheme.MENU_ROOT);
		content02View = new CssLayout();
		
		Label cLabel = new Label("ContentView");
		Label head = new Label("LeftMenu");
		head.addStyleName(ValoTheme.MENU_TITLE);


		leftMenu.addComponent(head);
		leftMenu.addComponent(showTitleView());

		content02View.addComponent(cLabel);

		allView.addComponent(leftMenu);
		allView.addComponent(content02View);
		allView.setSizeFull();

		addComponent(topMenu);
		addComponent(allView);

		title.addClickListener(event ->
		  title.setCaption("You pushed it!"));

	}

	private Button showTitleView() {
		title = new Button("Title", new Button.ClickListener() {
			@Override
			public void buttonClick(ClickEvent event) {
				content02View.removeAllComponents();
				content02View.addComponent(new TitleView(service));
			}
		});
		return title;
	}
}
package org.app.ui.masterdetail.views;

public class TitleView extends VerticalLayout implements View {

	public TitleView(TitleService service) {
		Label label01 = new Label("List1 of Title");
		addComponent(label01);
		Label label02 = new Label(service.getTitle(2).getTitle());
		addComponent(label02);
	}
}

I tried to make it so, but it doesn’t work.

My Question:

How can i show in my Case the content of TitleView in the area of Content02View?

17048397.png

Hi,
I see some problems here

  1. In MainView it seems you are not using the injected CdiViewProvider
    navigator.addProvider(viewProvider)
    Doing so all @CDIView annotated classes will be automatically managed and their dependencies will be injected.
  2. Remove manually registerd views (addView(..., new ...)) if they need some kind of injection.
  3. Put the correct view name in @CDIView annotation.
    Eg on MasterDetailView you should have @CDIView("MasterDetail"), PersonView should have @CDIView("Person"), LoginView should have @CDIView("") and so on
  4. Remove @PushStateNavigation from TopMenu because it is useless

This should work, but I didn’t tried it.
If you have troubles, please share the whole project (on github or as an attached zip) so it will be easier to point you to the correct solution.

HTH
Marco

I have tried to edit your suggestions.
I dont know how to make:

Remove manually registerd views (addView(…, new …)) if they need some kind of injection.

I have created a repo on github.
you can clone it with:

https://github.com/haglo/pilgerapp.git

It is OpenSource.

A lot of thanks.

Sorry for late response but it took me a while to get your project up and running.

This is what I changed to make it work:

  1. In web.xml you have defined the standard VaadinServlet but you should use com.vaadin.cdi.server.VaadinCDIServlet
  2. In MainView remove all navigator.addView(...) calls and use CDIViewProvider
  	/*
  	 * Register View to Navigator
  	 */
  	navigator = new Navigator(this, content01View);
  	navigator.addProvider(viewProvider);
  	/*  Remove all the following
  	navigator.addView("", new LoginView());
  	navigator.addView(PERSON_VIEW, new PersonView());
  	navigator.addView(MASTER_DETAIL_VIEW, new MasterDetailView());
  	navigator.addView(HELP_VIEW, new HelpView());
  	*/
  1. Remove @PushStateNavigation from MainView; it seems it has some troubles when running with CDI
    See https://github.com/vaadin/framework/issues/10633, https://github.com/vaadin/cdi/issues/242 and https://vaadin.com/forum/thread/16972282
  2. Add @CDIView("") to LoginView
  3. In PersonView fix the @CDIView annotation; it should be @CDIView("Person"), not @CDIView("PersonView") (even better @CDIView(MainView.PERSON_VIEW))
  4. Since TitleView is manually instantiated its init method will not be invoked

Side note: it seems to me that NaturalPersonEJB has an incorrect annotation @Remote(NaturalPerson.class); shouldn’t it be @Remote(NaturalPersonDAO.class)?

HTH
Marco

A lot of thanks.

Now it works perfect. Without your help i would have no chance.
I have commited the code.

But first i must study now the code why it works now. In the moment it is a little bit still magic.

Now i understand how it works. Its very great!!!

Very simple and very great!!!

One more question, but not so important (because it works)

Is there another way to call TitleView from MasterDetailView, to be shown in Content02View.

public void buttonClick(ClickEvent event) {
	content02View.removeAllComponents();
	content02View.addComponent(new TitleView(service));
}

Or is this best practice?

Or is this best practice?

It is not a best practice, it is just one of the multiple ways you can do it.
It highly depends on your use cases and how your app is structured.

a lot of thanks

Glad I could help

Regards
Marco