@NormalViewScoped - How does it exactly work?

Hello,

I’m facing a ‘problem’ here witch I can solve very easily. However, this ‘solution’ is more some kind of bypass or evasion of my problem. Let me explain my situation.

I’ve built an trigger-listener-architecture in Vaadin & CDI. Basically, my application uses tables for displaying data and modal boxes for altering data. So there are two kinds of controllers (=listeners):
SingleEntity
Controllers and
EntityTable
Controllers. Every action that considers amounts of datas is handled by the TableControllers; Every action that considers a single entity is handled by SingleEntityControllers. So basically two controllers are necessary per Entity-Class. These controllers react on events only if the corresponding beans already exist in memory (

@Observes(notifyObserver = Reception.IF_EXISTS

). So far, so good.

On entering a view, the injected EntityTableController gets to know it’s corresponding table by a simple setter invocation. This seemed to be necessary in older Vaadin CDI versions and can probably now be replaced by an Injection-solution, but I’m not planning to change that. The EntityTableController therefore is correctly instantiated, no problem is faced.
But additionally to the EntityTableController, a SingleEntityController is necessary for the application to work properly.

Problem is:
A simple injenction of any NormalViewScoped Bean into a View does not seem to be sufficient for instantiating it.
I’m currently evading this problem by a simple setter-invocation on the injected SingleEntityController - unnecessary overhead and ugly style. I need to use proxies here, so @ViewScoped is not really an option.

Is this behaviour intended or is this a bug?

I did a quick test with Vaadin CDI 1.0.3 (on Wildfly 8), and a @NormalViewScoped test bean is injected just fine into a view annotated with @CDIView (which is by default @ViewScoped). A @PostConstruct method in the NVS bean is executed, and in the view enter method (or a @PostConstruct method) the NVS bean @PostConstruct has been run.

As the javadoc mentions, the two scopes (@ViewScoped and @NormalViewScoped) share the same internal underlying scope/context so the same instance should be injectable through either one.

In the case of the latter, a proxy is used so interceptors etc. work, but with some CDI implementations the equals() and hashCode() methods “misbehave” so injecting a component in a normal scope is problematic.

I do recall there were some issues with Reception.IF_EXISTS etc. with older versions of Vaadin CDI (some perhaps due to issues in the version of DeltaSpike that was used by them), and some were fixed in Vaadin CDI 1.0.3. Which version of Vaadin CDI are you using?

If there are still problems specifically e.g. with Reception.IF_EXISTS, could you provide a code sample demostrating the problem.

Hi Henri,

thanks for the response. Yes, I’m using Vaadin CDI 1.0.3 and I’m always trying to use the latest version.

I know the difference between @ViewScoped and @NormalViewScoped; I need to use @NormalViewScoped because of some cirular references.
As the Vaadin documentation says, using normal scoped injections together with components may cause problems. Maybe that’s the cause. I will provide some example code soon.

Greetings!

Example Code:


ViewComponent.class

[code]
public abstract class ViewComponent extends VerticalLayout implements View {

protected Logger logger;

public ViewComponent() {
super();
buildLayout();
logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
}

protected void buildLayout() {

this.setImmediate(true);
this.setHeight(“100%”);
this.setWidth(“100%”); }

@Override public void enter(ViewChangeEvent e) { }

}
[/code]
ExampleView.class:
[code]
@CDIView(“example”)
public class ExampleView extends ViewComponent {

@Inject
private ExampleTableController exampleTableController;
@Inject
private SingleExampleController singleExampleController;
@Inject
private ExampleFilterTable exampleFilterTable;

public SemestersView() {
super();
}

@PostConstruct
public void init() {

singleExampleSemesterController.setView(this); //This causes the SingleExampleController to instantiate
exampleTableController.setCorrespondingTable(exampleFilterTable); //This causes the ExampleTableController to instantiate

this.addComponent(exampleFilterTable);

}
[/code]
AbstractSingleEntityController.class:

[code]
public abstract class AbstractSingleEntityController implements EntityActionEventListener {

private Class clazz;
protected View correspondingView;

public AbstractSingleEntityController(Class clazz) {
this.clazz = clazz;
}

public void listenTo(@Observes(notifyObserver=Reception.IF_EXISTS) EntityActionEvent event) throws Exception {
if (event.getEventTargetClass().isAssignableFrom(clazz)) {
doSomething();
}
}
[/code]Note that every implementation of AbstractSingleEntityController/AbstractTableController is a NormalViewScoped bean. Basically, AbstractSingleEntityController and AbstractTableController do not differ from each other.