Facelets --- LifecycleRätsel


#1

Hi!

Ich habe hier eine neue JSF2.2App@Tomcat8.0. Gebaut mit Netbeans 8.1

**Das Problem kurz erklärt: **
Template mit Inserts für Left und Content.

Left: Enthält ein Formular, welches an eine Bean im SessionScope gebunden ist. Ein CommandButton gebunden an eine Action in der nichts passiert ausser return “”

Content: Ein OutputText, gebunden an eine RequestScopedBean, welche die o.g. SessionScopedBean, als ManagedProperty enthält. Es soll ein Property der SessionScopedBean angezeigt werden. Im PostConstruct der RequestScopedBean wir ein Property gesetzt, wenn der Eingegebene Text länger, als 10 ist. Wenn dieses Property true ist, dann soll der OutputText nicht gerendert werden.

Das Problem:
Eigentlich sollte nach betätigen des CommandButton die Action der SessionScopedBean ausgeführt werden und erst dann die PostConstruct der RequestScopedBean.

Im Fall von <h:outputText value="#{requestScopedBean.sessionBean.userName}" /> läuft das so korrekt ab.

Sobald <h:outputText value="#{requestScopedBean.sessionBean.userName}" rendered="#{requestScopedBean.showUserName2}" /> in der XHTML steht, dann wird die Reihenfolge umgedreht, sodass erst die PostConstruct und erst dann die Action aufgerufen wird. Das ist doof, da die Eingabe früher ausgewertet wird, als sie in der SessionScopedBean aktualisiert wurde.

Wo liegt das Problem? bzw. wie kann ich erzwingen, dass die Action der SessionScopedBean zuerst aufgerufen wird.

Der Code, als zip:

Die wichtigsten Sachen gekürzt hier
Content
[XML]<ui:composition template="./newTemplate.xhtml">
<ui:define name=“content”>
Username1: <h:outputText value="#{requestScopedBean.sessionBean.userName}" />

Username2: <h:outputText value="#{requestScopedBean.sessionBean.userName}" rendered="#{requestScopedBean.showUserName2}" />
</ui:define>
</ui:composition>[/XML]

requestScopedBean

    public void init(){
        if(sessionBean.getUserName().length() > 10){
            showUserName2 = false;
        }else{
            showUserName2 = true;
        }
    }```

sessionScopedBean
```@ManagedBean
@SessionScoped
//@ApplicationScoped
public class SessionScopedBean {

    private String userName = "";
    
    public String action(){

        
        return "";
    }
    

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
    
}```

CommandLink --- ActionMethode wird nicht aufgerufen
#2

Hallo,

Richtig wäre: Es wird zunächst PostConstruct ausgeführt und dann die Action. Warum das in Deinem einen Fall anders ist, klingt nach einem Fehler.

Raten würde ich Dir auf CDI zu wechseln, da die Standard-JSF-Annotationen nur für den Übergang zu CDI gedacht waren. Als JSF2 auf den Markt kam, war CDI noch nicht so weit, deshalb gab es ein eigenes DI.

Zu Deinem aktuellen Problem: Kannst Du das, was Du im PostConstruct machst, nicht einfach in der Action-Methode tun?


#3

Danke! :slight_smile:

Das ist natürlich super, denn default ist es bei mir genau umgekehrt. Erst wenn rendered in einem JSF-Tag steht, dann ist es, wie Du es schreibst.

Die Postconstruct existiert in diesem Beispiel nur, um an geeigneter Stelle einen BreakPoint setzten zu können, damit man den Spaß untersuchen kann. Wichtig ist in dem Fall nur das rendered funktioniert, wenn in der SessionScopedBean etwas besonderes drinsteht. Natürlich könnte ich das mit JavaScript erledigen.

Ich hoffe doch nicht, dass es ein JSF-Bug ist, denn ich qualvoll umgehen muß.

Das scheint es auf dem Tomcat nicht zu geben.


#4

CDI geht auch mit dem Tomcat. Es muss nur entsprechend eingerichtet werden. JSF gehört ja auch nicht zum Default-Tomcat-Stack :slight_smile:

Aber debuggen kannst Du doch auch die Actionmethode. Da kannst Du die Sessionbean ja direkt auslesen. Es werden erst die Felder submitted und dann die Action aufgerufen. Oder hast Du damit Probleme?


#5

Ja klar :slight_smile: … Ohne rendered werden die Methoden in der Reihenfolge aufgerufen aufgerufen
1 SessionScopedBean Action mit den submiteten Feldern
2 RequestScopedBean Postconstruct. Die felder bekomme ich von der SessionScopedBean
Das passt

Sobald ein rendered in der XHTML steht dann ist die Reihenfolge so
1 RequestScopedBean PostConstruct. Die Daten der Felder werden jetzt gebraucht, aber wurden noch nicht submittet
2 SessionScopedBean Action und erst jetzt werden die Daten submittet
Das passt nicht


#6

Wenn ich den Button drücke der SessionScopedBean.Action() auslöst, welche Methode soll als erstes laufen?

  • SessionScopedBean.Action
    oder
  • RequestScopedBean.Postconstruct

#7

Hi,

PostConstruct sollte meines Wissens nach direkt nach dem Konstruktor aufgerufen werden, damit also vor der Action.


#8

Das schon, aber in dem Fall haben wir 2 Beans und die SessionScopedBean überlebt einige PostConstructs der RequestScopedBean.


#9

Die ZIP aus meinem ersten Post ist verschwunden. Hier noch nochmal: Jsf2.2Test.zip (5,6 KB)


#10

Ist die Frage denn noch aktuell?


#11

Doch, ja :slight_smile: Immer noch aktuell und immer noch ein Rätsel für mich.