public void onEdisonProjectUpdated(@Observes EdisonProjectUpdatedEvent e)Developing Vaadin with all the "make-easy" techniques can just hides complexity and in fact drive me insane when something went wrong. Also when all these things from different party plays together - they don't often plays well.
So when I survived one insanity scenario, I record it down to avoid future insanity attach :)
FIRST READ "ENVIRONMENT" to get the environment correct!
When nothing specified:
@CDIView(ViewCat.DEBUG)
public class DebugView extends VerticalLayout implements View{
........
@Inject
public DebugView(EdisonDataProvider provider) {
System.out.println("Debug View Initiated"+this.toString());
Every time the view is navigated to, a new instance is created.
If I change the view to session scoped.
@CDIView(ViewCat.DEBUG)
@SessionScoped
public class DebugView extends VerticalLayout implements View, Serializable{
......
@Inject private EdisonDataProvider dataProvider;
@PostConstruct
public void initialize() {
Note when SessionScope is used, the bean will be proxyed, and that means a default (no-argument) constructor must be provided and also for bean in session scope, it muse implements the Serializable interface.
Both somehow works. Until not (read next)
@SessionScoped
@CDIView(ViewCat.RESULT_DEFAULT)
public class DefaultProjectView extends HorizontalSplitPanel implements View{
....
public DefaultProjectView() {
...
};
@PostConstruct
public void postConstruction() {
...
}
@Override
public void enter(ViewChangeEvent event) {
}
public void onClaimSetUpdated(@Observes ClaimSetUpdatedEvent e){
// nothing
}
public void onEdisonProjectUpdated(@Observes EdisonProjectUpdatedEvent e){
// nothing
}
public void onFocusedClaimSlectedEvent(@Observes FocusedClaimSelectedEvent e) {
// rightTabSheet.setSelectedTab(singleClaimView);
}
This is what happened.
First, when "public void onEdisonProjectUpdated(@Observes EdisonProjectUpdatedEvent e)" was not in the code, it works (contents show up);
Then, after I added public "void onEdisonProjectUpdated(@Observes EdisonProjectUpdatedEvent e)", even later removed any code inside it (so made it empty), it no longer work. This is when I was mad but, with past experience, quickly figured out it's the SCOPE!!! SCOPE!!! SCOPE!!! SCOPE!!! SCOPE!!!
What happened is, two instances of the DefaultProjectView was constructed (instead of desired, one, as the case when it works). One was instantiated when navigating to the DefaultProjectView, another was instantiated when fired the event EdisonProjectUpdatedEvent. Interestingly, the first time creating a DefaultProjectView instance (navigate to), a proxy-ed instance was constructed. The second time, a non-proxyed (for observing event). Why? I don't know....
Then again, if I remove @SessionScoped and retain the "void onEdisonProjectUpdated" method, it works again... until another event was observed (and then a new instance created again, not desired).. so still not working
I'm re-creating yesterday evening's problems and will examine here what works / not works and what's learnt
package com.inno4g.edison.view.debug;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import com.inno4g.workchamp.cdi.Tag;
import com.inno4g.workchamp.vaadin.command.ActionTriggeredEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
@Dependent
public class GrowingView extends VerticalLayout {
public GrowingView() {
System.out.println("\n@@@@@@@ Initializaing Growing View "+this.toString());
}
@Inject @Tag("DEBUGCLICK")
javax.enterprise.event.Event<ActionTriggeredEvent> event;
@PostConstruct
public void initialize() {
addComponent(new Label("First Label"));
Button click = new Button("Click me");
click.addClickListener(button -> {
System.out.println("\n@@@@@@@ button clicked, about to fire with "+event.toString());
event.fire(new ActionTriggeredEvent());
});
}
public void onDebugClick(@Observes @Tag("DEBUGCLICK") ActionTriggeredEvent e) {
System.out.println("\n@@@@@@@ onDebug called, handling with "+this.toString());
addComponent(new Label("\n@@@@@@@ More Components"));
}
}
Here's the initial code, noted:
Answer to the above through observation:
Now change "event.toString()" - which does not output object's "id hashcode", to "System.identityHashCode(event)"
22:53:33,003 INFO [stdout] (default task-7) @@@@@@@ Initializaing Growing View com.inno4g.edison.view.debug.GrowingView@2610b1d4
22:53:33,003 INFO [stdout] (default task-7)
22:53:33,003 INFO [stdout] (default task-7) @@@@@@@ post construct, event object is 907240411
22:53:37,874 INFO [stdout] (default task-7)
22:53:37,874 INFO [stdout] (default task-7) @@@@@@@ onDebug called, handling with com.inno4g.edison.view.debug.GrowingView@2610b1d4
22:53:50,639 INFO [stdout] (default task-6)
22:53:50,639 INFO [stdout] (default task-6) @@@@@@@ button clicked, about to fire with 1261421341
22:53:50,640 INFO [stdout] (default task-6)
22:53:50,640 INFO [stdout] (default task-6) @@@@@@@ Initializaing Growing View com.inno4g.edison.view.debug.GrowingView@7bb45e19
22:53:50,641 INFO [stdout] (default task-6)
22:53:50,641 INFO [stdout] (default task-6) @@@@@@@ post construct, event object is 2004166040
22:53:50,641 INFO [stdout] (default task-6)
22:53:50,641 INFO [stdout] (default task-6) @@@@@@@ onDebug called, handling with com.inno4g.edison.view.debug.GrowingView@7bb45e19
22:53:52,128 INFO [stdout] (default task-8)
22:53:52,128 INFO [stdout] (default task-8) @@@@@@@ button clicked, about to fire with 1261421341
22:53:52,129 INFO [stdout] (default task-8)
22:53:52,129 INFO [stdout] (default task-8) @@@@@@@ Initializaing Growing View com.inno4g.edison.view.debug.GrowingView@2579a0dc
22:53:52,129 INFO [stdout] (default task-8)
22:53:52,129 INFO [stdout] (default task-8) @@@@@@@ post construct, event object is 337019672
22:53:52,129 INFO [stdout] (default task-8)
22:53:52,129 INFO [stdout] (default task-8) @@@@@@@ onDebug called, handling with com.inno4g.edison.view.debug.GrowingView@2579a0dc
Now change @Dependent to @SessionScoped to see if it should work
@SessionScoped
public class GrowingView extends VerticalLayout implements Serializable {
Now add printout "this" inside lamdba
One more thing, what's the difference between lambda and anonymous inner class? Try to implement another button which uses an anonymous class as event listener.
Button click = new Button("Click me handled by lambda");
System.out.println("\n@@@@@@@ post construct, event object is "+System.identityHashCode(event));
click.addClickListener(button -> {
System.out.println("inside lambda - what is this? "+this.toString());
System.out.println("\n@@@@@@@ button clicked, about to fire with "+System.identityHashCode(event));
event.fire(new ActionTriggeredEvent());
});
addComponent(click);
Button clickInnerClass = new Button("Click me handled by inner class");
clickInnerClass.addClickListener(
new ClickListener() {
@Override
public void buttonClick(ClickEvent clickEvent) {
System.out.println("inside anonymous class - what is this? "+this.toString());
System.out.println("\n@@@@@@@ button clicked, about to fire with "+System.identityHashCode(event));
event.fire(new ActionTriggeredEvent());
}
}
);
addComponent(clickInnerClass);
Above codes have two buttons side by side, one implemented with a lambda expression, the other an inner class. Both works, but they work differently.
Lambda: the click handler is the class instance itself
inside lambda - what is this? com.inno4g.edison.view.debug.GrowingView@18f8fb7
Anonymous class: an instance of the anonymous class, the same instance.
inside anonymous class - what is this? com.inno4g.edison.view.debug.GrowingView$1@4768154c
Wait a minute, confused again. what's exactly a lambda? (NEED TO READ) when I add a line "Object x = null; x.toString(); // intentionally create problem" to intentionally creates a problem, the stack print is:
at com.inno4g.edison.view.debug.GrowingView.lambda$initialize$61446b05$1
Is it a method? inner class? what's that?
I was writing views that was injected into another view (layout) and also observes event that the view should update itself. Everything looks good, no error, no exception, but the view just doesn't update itself on browser.... this drove me crazy for several hours and I even developed a (wrong) theory that the layout does not grow with the view update, so the view in fact updated itself, just the change is hidden.... then, finally, I get it,
the reason is the WRONG SCOPE of that view
I made it @Dependent, and with a @Dependent bean:
That was ok for the purpose of my view - it depends on the view containing it anyway. But when container wants a bean (the view) to handle the event being fired, it did not locate the previously initiated bean, but instantiated a new one. Then the new view is updated - all behind the curtain, and never put to the front.
Solution: make the bean @SessionScoped or have the containing view listen to the event
No, latest update,@SessionScoped vaadin component don't work well. Use its own UIScoped/ViewScoped, etc., see another part of my note!
Removed class file still in deployed package, sometimes leading confusion (CDI)
Seems restart Eclipse first.
17:51:09,943 INFO [com.vaadin.cdi.internal.ContextDeployer] (ServerService Thread Pool -- 70) 0 beans inheriting from UI discovered!
17:42:49,444 WARNING [com.vaadin.cdi.internal.ContextDeployer] (ServerService Thread Pool -- 61) No Vaadin UI classes with @CDIUI annotation found. Skipping automated deployment of VaadinCDIServlet.
When of course @CDIUI is there. Then the real problem, I found, is deploy directory has no classes.
Solution:
tried project context menu -> Maven -> update project, and it seems ok then... not sure about next time
someone here said he think "WTP don't work well when change things in background (maven build)" so his solution is to avoid using that at all. He uses maven solely with perhaps shell scripts.
Yes, FINALLY I found, after failed EVERYTHING, I need to restart Eclipse. So I agree, "run on server" from Eclipse does not work well with Maven. Use Maven goal.