Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Java  Module 23 – Jakarta Faces (JSF): component-based web UIs

The Faces life cycle, phase by phase

Follow a Faces request through Restore View, Apply Request Values, Process Validations, Update Model Values, Invoke Application and Render Response.

  • Advanced
  • 25 minutes
  • Examples run with Java 25.0.4 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 8 of 25 minutes free
Free: The six phases · Watching the phases with a phase listener · Three requests, recorded · 2 more sections. With a pass: 3 in-depth parts and 3 interview answers, about 17 minutes.

What you will learn

  • Name the six phases and what each one does to the component tree
  • Predict the phases of a first request, a valid post and a post that fails validation
  • Use immediate, a phase listener and the view state to observe and control processing

Before you start

The Faces life cycle is the fixed order of six phases in which Faces handles every request for a page: Restore View, Apply Request Values, Process Validations, Update Model Values, Invoke Application and Render Response. Each phase does one job to the page’s component tree. The first restores the tree, or builds it for a first visit. The second gives each component its submitted text, and the third converts and validates that text. The fourth copies the valid values into the beans, the fifth runs the action of the button that was pressed, and the sixth writes the HTML and saves the view. A first GET needs only phases 1 and 6. A post runs all six, unless a value fails: then Faces jumps from phase 3 to phase 6 and never touches the beans.

This lesson follows the Faces life cycle phase by phase on a course-registration form, with a phase listener that records every phase, setter and action. The recordings ran on Mojarra 4.1.18, Tomcat 11.0.26 and Eclipse Temurin 25.0.4.1.

The six phases

The six Faces phases in order, from Restore View to Render Response, and the three cases that jump to Render Response.1 Restore Viewbuilds the tree, or restores the saved oneA first request goes on to phase 62 Apply Request Valueseach component takes its submitted textAfter an immediate action: phase 63 Process Validationsconverts and validates, queues messagesIf a value fails: phase 64 Update Model Valuesvalid values go into the beans5 Invoke Applicationthe pressed button's action runs6 Render Responsewrites the HTML, saves the viewa postevery value valid

The six phases of a Faces request, and when a request jumps to the last one

Text description of the diagram

Six boxes stand in one column, joined by arrows from top to bottom.

  1. Restore View builds the component tree, or restores the saved one. A first request goes on to phase 6. The arrow to the next box is labelled "a post".
  2. Apply Request Values: each component takes its submitted text. After an immediate action, the request goes on to phase 6.
  3. Process Validations converts and validates the values and queues messages. If a value fails, the request goes on to phase 6. The arrow to the next box is labelled "every value valid".
  4. Update Model Values: the valid values go into the beans.
  5. Invoke Application: the action of the pressed button runs.
  6. Render Response writes the HTML and saves the view.
Phase What it does to the tree Your code it calls
1 Restore View Restores the saved tree on a post, or builds a new one None
2 Apply Request Values Each input stores its submitted text, and the pressed button queues its action The actions of immediate buttons
3 Process Validations Converters turn the text into values, validators check them, and failures queue messages Validators and value-change listeners
4 Update Model Values Each valid value goes into the bean through its expression Setters
5 Invoke Application The queued actions run, and Faces picks the view to show next Action methods and action listeners
6 Render Response The tree writes the HTML, and the view state is saved Getters

The phases are the constants of jakarta.faces.event.PhaseId, numbered 1 to 6, and ANY_PHASE stands for all of them.

Watching the phases with a phase listener

A PhaseListener is called before and after the phases that its getPhaseId() names. PhaseTrail names ANY_PHASE and adds each phase to a list kept in the request’s FacesContext; the bean’s setters and actions add their own lines, and the page prints the list:

The lifecycle application

Java (PhaseTrail.java) · lifecycle/src/main/java/com/example/lifecycle/PhaseTrail.java

package com.example.lifecycle;

import jakarta.faces.event.PhaseEvent;
import jakarta.faces.event.PhaseId;
import jakarta.faces.event.PhaseListener;

/**
 * Adds the name of every phase to the request's trail as the phase begins. ANY_PHASE asks Faces to call it before and
 * after each of the six phases; faces-config.xml registers it.
 */
public class PhaseTrail implements PhaseListener {

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }

    @Override
    public void beforePhase(PhaseEvent event) {
        Trail.of(event.getFacesContext()).add(event.getPhaseId().toString());
    }

    @Override
    public void afterPhase(PhaseEvent event) {
    }
}

Java (Registration.java) · lifecycle/src/main/java/com/example/lifecycle/Registration.java

package com.example.lifecycle;

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;

/** The backing bean of form.xhtml. Its setters and actions note in the trail when Faces calls them. */
@Named
@RequestScoped
public class Registration {

    private String name;
    private Integer semester;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        Trail.add("  setName(\"" + name + "\")");
        this.name = name;
    }

    public Integer getSemester() {
        return semester;
    }

    public void setSemester(Integer semester) {
        Trail.add("  setSemester(" + semester + ")");
        this.semester = semester;
    }

    public void save() {
        Trail.add("  save()");
    }

    public void cancel() {
        Trail.add("  cancel()");
    }
}

XHTML · lifecycle/src/main/webapp/form.xhtml

<!DOCTYPE html>
<!-- A registration form whose page also shows what Faces did for this request: the trail of phases, setters and
     actions, the values the bean holds while the page is rendered, and the messages. -->
<html lang="en" xmlns:h="jakarta.faces.html" xmlns:f="jakarta.faces.core" xmlns:ui="jakarta.faces.facelets">
<h:head>
  <title>Course registration</title>
</h:head>
<h:body>
  <h1>Course registration</h1>
  <h:form id="reg">
    <h:outputLabel for="name" value="Name"/>
    <h:inputText id="name" label="Name" value="#{registration.name}" required="true"/>
    <h:outputLabel for="semester" value="Semester"/>
    <h:inputText id="semester" label="Semester" value="#{registration.semester}" required="true">
      <f:validateLongRange minimum="1" maximum="8"/>
    </h:inputText>
    <h:commandButton id="save" value="Save" action="#{registration.save}"/>
    <!-- immediate: the action runs at the end of Apply Request Values, before any validation. -->
    <h:commandButton id="cancel" value="Cancel" action="#{registration.cancel}" immediate="true"/>
  </h:form>
  <h:messages id="messages"/>
  <p id="stored">name=#{registration.name}, semester=#{registration.semester}</p>
  <ol id="trail">
    <ui:repeat value="#{trailView.steps}" var="step"><li class="step">#{step}</li></ui:repeat>
  </ol>
</h:body>
</html>

XML · lifecycle/src/main/webapp/WEB-INF/faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Registers the phase listener for every request of the application, and declares admin.xhtml a protected view. -->
<faces-config xmlns="https://jakarta.ee/xml/ns/jakartaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_1.xsd"
              version="4.1">
  <lifecycle>
    <phase-listener>com.example.lifecycle.PhaseTrail</phase-listener>
  </lifecycle>
  <protected-views>
    <url-pattern>/admin.xhtml</url-pattern>
  </protected-views>
</faces-config>

Java (Trail.java) · lifecycle/src/main/java/com/example/lifecycle/Trail.java

package com.example.lifecycle;

import jakarta.faces.context.FacesContext;
import java.util.ArrayList;
import java.util.List;

/**
 * The steps of the current request: the phases as they begin, and the setters and actions that run in them. The list
 * lives in the request's FacesContext, which Faces creates for each request and drops at its end.
 */
public final class Trail {

    private static final String KEY = Trail.class.getName();

    private Trail() {
    }

    @SuppressWarnings("unchecked")
    public static List<String> of(FacesContext context) {
        return (List<String>) context.getAttributes().computeIfAbsent(KEY, key -> new ArrayList<String>());
    }

    public static void add(String step) {
        of(FacesContext.getCurrentInstance()).add(step);
    }
}

Visit.java plays the browser. It loads the page, posts the form back with the page’s hidden fields and the values on its command line, and prints the trail, the text in the fields, what the bean held while the page was rendered, and the messages:

Visit.java Java · Visit.java
// Plays a browser against a page of the lifecycle application and prints what the page reports about each request.
//
//   java Visit.java <page URL>                        loads the page with a GET
//   java Visit.java <page URL> <field>=<value> ...    loads the page, then posts its form back with these fields
//
// A post carries what a browser sends: the hidden fields of the page it loaded (the form's id and the
// jakarta.faces.ViewState field) and the fields given, among them the button that was pressed (reg:save=Save). A
// field given as an empty value (reg:name=) is posted empty. Options, in the place where they apply:
//
//   --then               posts again, from the answer of the post before, with the fields that follow
//   --view-state=none    leaves the view state out of the post; --view-state=<value> sends that value instead
//   --tamper             changes one character in the middle of the view state before posting it
//   --new-session        posts without the session cookie, as a browser does once its session has expired
//   --state-size         prints the length of the page's view state field
//   --follow=<id>        instead of posting, follows the link with that id, from the page, as a browser would
//
// For each answer it prints the request and the status, the steps of the page's trail, the values shown in the
// form's text fields, what the bean held while the page was rendered, and the messages.

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

static final String VIEW_STATE = "jakarta.faces.ViewState";
static final Pattern HIDDEN = Pattern.compile("<input type=\"hidden\" name=\"([^\"]+)\"[^>]*? value=\"([^\"]*)\"");
static final Pattern TEXT_FIELD = Pattern.compile("<input id=\"([^\"]+)\" type=\"text\" name=\"[^\"]+\" value=\"([^\"]*)\"");
static final Pattern STEP = Pattern.compile("<li class=\"step\">(.*?)</li>");
static final Pattern STORED = Pattern.compile("<p id=\"stored\">(.*?)</p>");
static final Pattern MESSAGES = Pattern.compile("<ul id=\"messages\">(.*?)</ul>");
static final Pattern MESSAGE = Pattern.compile("<li>\\s*(.*?)\\s*</li>");

final CookieManager cookies = new CookieManager();
HttpClient browser = HttpClient.newBuilder().cookieHandler(cookies).build();

void main(String[] args) throws Exception {
    URI page = URI.create(args[0]);
    HttpResponse<String> answer = browser.send(HttpRequest.newBuilder(page).build(), BodyHandlers.ofString());
    List<String> rest = List.of(args).subList(1, args.length);
    if (rest.stream().noneMatch(a -> a.contains("=") && !a.startsWith("--state-size"))) {
        report("GET " + page.getPath(), answer, rest.contains("--state-size"));
        return;
    }
    List<String> fields = new ArrayList<>();
    for (String arg : rest) {
        if (arg.equals("--then")) {
            answer = post(page, answer, fields);
            fields = new ArrayList<>();
        } else {
            fields.add(arg);
        }
    }
    post(page, answer, fields);
}

/** Posts the form of the page in `before` back with these fields, prints the answer and returns it. */
HttpResponse<String> post(URI page, HttpResponse<String> before, List<String> fields) throws Exception {
    Optional<String> follow = fields.stream().filter(f -> f.startsWith("--follow=")).findFirst();
    if (follow.isPresent()) {
        String id = follow.get().substring("--follow=".length());
        Matcher link = Pattern.compile("<a id=\"" + Pattern.quote(id) + "\"[^>]*? href=\"([^\"]+)\"").matcher(before.body());
        if (!link.find()) throw new IllegalStateException("the page has no link with the id " + id);
        URI target = page.resolve(text(link.group(1)));
        HttpRequest get = HttpRequest.newBuilder(target).header("Referer", page.toString()).build();
        HttpResponse<String> answer = browser.send(get, BodyHandlers.ofString());
        report("GET " + target.getPath() + " (link " + id + ")", answer, false);
        return answer;
    }
    Map<String, String> form = new LinkedHashMap<>();
    HIDDEN.matcher(before.body()).results().forEach(m -> form.put(m.group(1), m.group(2)));
    for (String field : fields) {
        if (field.equals("--view-state=none")) {
            form.remove(VIEW_STATE);
        } else if (field.startsWith("--view-state=")) {
            form.put(VIEW_STATE, field.substring("--view-state=".length()));
        } else if (field.equals("--tamper")) {
            String state = form.get(VIEW_STATE);
            int middle = state.length() / 2;
            form.put(VIEW_STATE, state.substring(0, middle) + (state.charAt(middle) == 'A' ? 'B' : 'A') + state.substring(middle + 1));
        } else if (field.equals("--new-session")) {
            cookies.getCookieStore().removeAll();
        } else if (!field.startsWith("--")) {
            int eq = field.indexOf('=');
            form.put(field.substring(0, eq), field.substring(eq + 1));
        }
    }
    String body = form.entrySet().stream()
            .map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));
    HttpRequest post = HttpRequest.newBuilder(page)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
    HttpResponse<String> answer = browser.send(post, BodyHandlers.ofString());
    report("POST " + String.join(" ", fields), answer, fields.contains("--state-size"));
    return answer;
}

void report(String request, HttpResponse<String> answer, boolean stateSize) {
    String html = answer.body();
    IO.println(request + " -> " + answer.statusCode());
    STEP.matcher(html).results().forEach(m -> IO.println("  " + text(m.group(1))));
    List<String> shown = TEXT_FIELD.matcher(html).results().map(m -> m.group(1) + "=" + text(m.group(2))).toList();
    if (!shown.isEmpty()) IO.println("fields show: " + String.join(", ", shown));
    Matcher stored = STORED.matcher(html);
    if (stored.find()) IO.println("bean while rendering: " + text(stored.group(1)));
    Matcher list = MESSAGES.matcher(html);
    List<String> messages = list.find() ? MESSAGE.matcher(list.group(1)).results().map(m -> text(m.group(1))).toList() : List.of();
    IO.println("messages: " + (messages.isEmpty() ? "none" : String.join(" | ", messages)));
    if (stateSize) {
        HIDDEN.matcher(html).results().filter(m -> m.group(1).equals(VIEW_STATE))
                .forEach(m -> IO.println("view state field: " + m.group(2).length() + " characters"));
    }
}

/** The text of an HTML fragment: the five entities Faces writes, decoded. */
String text(String html) {
    return html.replace("&quot;", "\"").replace("&#39;", "'").replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&");
}

Three requests, recorded

Read each trail phase by phase, against the table above:

A first GET, a valid post and a post with semester 9 Python · lifecycle_session.py
from session import run

# Builds the lifecycle application, deploys it to a new Tomcat base on 127.0.0.1:28650 and sends three requests with
# Visit.java: the first GET, a post that passes validation, and a post with a semester out of range.
run(
    """
cd lifecycle
mvn -q package
cd ..
sh new-base.sh base 28650
cp lifecycle/target/lifecycle.war base/webapps/
$CATALINA_HOME/bin/startup.sh
java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml
java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml reg:name=Asha reg:semester=5 reg:save=Save
java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml reg:name=Asha reg:semester=9 reg:save=Save
$CATALINA_HOME/bin/shutdown.sh
""",
    port=28650,
)

Output

# openjdk version "25.0.4.1" LTS · Apache Maven 3.10.0 · Apache Tomcat 11.0.26
$ cd lifecycle
$ mvn -q package
$ cd ..
$ sh new-base.sh base 28650
$ cp lifecycle/target/lifecycle.war base/webapps/
$ $CATALINA_HOME/bin/startup.sh
$ java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml
GET /lifecycle/form.xhtml -> 200
  RESTORE_VIEW 1
  RENDER_RESPONSE 6
fields show: reg:name=, reg:semester=
bean while rendering: name=, semester=
messages: none
$ java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml reg:name=Asha reg:semester=5 reg:save=Save
POST reg:name=Asha reg:semester=5 reg:save=Save -> 200
  RESTORE_VIEW 1
  APPLY_REQUEST_VALUES 2
  PROCESS_VALIDATIONS 3
  UPDATE_MODEL_VALUES 4
    setName("Asha")
    setSemester(5)
  INVOKE_APPLICATION 5
    save()
  RENDER_RESPONSE 6
fields show: reg:name=Asha, reg:semester=5
bean while rendering: name=Asha, semester=5
messages: none
$ java Visit.java http://127.0.0.1:28650/lifecycle/form.xhtml reg:name=Asha reg:semester=9 reg:save=Save
POST reg:name=Asha reg:semester=9 reg:save=Save -> 200
  RESTORE_VIEW 1
  APPLY_REQUEST_VALUES 2
  PROCESS_VALIDATIONS 3
  RENDER_RESPONSE 6
fields show: reg:name=Asha, reg:semester=9
bean while rendering: name=, semester=
messages: Semester: Validation Error: Specified attribute is not between the expected values of 1 and 8.
$ $CATALINA_HOME/bin/shutdown.sh

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 lifecycle_session.py

  • The first GET ran Restore View and Render Response only. Nothing had been posted, so Restore View built the tree and sent the request straight to rendering.
  • The valid post ran all six phases. The setters ran in Update Model Values, save() in Invoke Application, and the page was rendered from the new values.
  • Semester 9 failed f:validateLongRange in Process Validations, and the request jumped to Render Response. The name Asha was valid, yet the bean received neither value, because Update Model Values runs for the whole form or not at all. The fields still showed Asha and 9: each component keeps the text it was sent until a post succeeds.
Request Phases Bean updated Action ran
A first GET 1, 6 No No
A post, every value valid 1 to 6 Yes Yes
A post with one invalid value 1, 2, 3, 6 No, not even the valid fields No

What else changes the order

Five things change the path above:

  • immediate="true" on a button runs its action at the end of Apply Request Values, before any validation.
  • immediate="true" on an input field converts and validates it in Apply Request Values instead.
  • A post without its jakarta.faces.ViewState field cannot be matched to a saved view.
  • Client-side state saving keeps the whole saved view in that field instead of the HTTP session.
  • A protected view refuses a GET that does not carry its session’s token.

GTU 3160707, unit 5

The syllabus of Advance Java Programming names the “JSF request processing Life cycle” among the topics of unit 5. Its six phases are the same in JSF 2.0 and Faces 4.1, so the recorded trails of this lesson answer that topic for either version.

Check yourself

Check yourself

4 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 4 Put the six phases of a Faces post in the order they run.

    Give each item its position, from 1 (first).

    Show the answer to question 1

    Answer:

    1. Restore View
    2. Apply Request Values
    3. Process Validations
    4. Update Model Values
    5. Invoke Application
    6. Render Response

    The recorded valid post ran exactly this order: the tree is restored, each component takes its submitted text, the text is converted and validated, the valid values go into the bean, the action runs, and the page is rendered and its view saved.

  2. Question 2 of 4 A post of the registration form sends a valid name and the semester 9, which f:validateLongRange rejects. Which phases run?

    Choose one answer.

    Show the answer to question 2

    Answer: Restore View, Apply Request Values, Process Validations, Render Response

    Validation fails in Process Validations, and Faces jumps from there to Render Response, skipping Update Model Values and Invoke Application. The recorded trail shows phases 1, 2, 3 and 6.

  3. Question 3 of 4 After that post, what does the request's bean hold while the page is rendered?

    Choose one answer.

    Show the answer to question 3

    Answer: Neither value, because Update Model Values did not run for any field

    Updating the model is all or nothing for the posted form: one invalid value keeps every value out of the bean. The recorded run shows "name=, semester=" in the bean while the fields still show Asha and 9, because each component keeps the text it was sent.

  4. Question 4 of 4 Why does a first GET of form.xhtml run only Restore View and Render Response?

    Choose one answer.

    Show the answer to question 4

    Answer: There is no submitted form to decode, so Restore View builds the tree and hands it straight to rendering

    A first request has no view state to restore and no values to process. Restore View builds a new tree and calls renderResponse(), so the phases in between are skipped, as the recorded GET shows.

immediate, step by step: Cancel, Back and immediate fields Pro: opens with a Pro, Premium or Ultimate pass

immediate moves work from later phases into Apply Request Values. Four recorded requests show what that does to a Cancel button, to a field marked immediate, and to the Back button of a form with two steps.

In this part:

  • Four requests with immediate, recorded
  • Why Cancel left the typed text in the form
  • A field marked immediate makes Cancel look broken
  • Back without validating the current step
  • Choosing a Cancel or Back that cannot be blocked: the trade-offs

2 runnable examples (Java, Python, XHTML) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

The view state: where it lives, and how posts lose it Pro: opens with a Pro, Premium or Ultimate pass

The jakarta.faces.ViewState field ties every post to a saved view. This part leaves the field out, forges it, outlives its session and tampers with it, and records what Faces did each time.

In this part:

  • Seven requests against the view state, recorded
  • Reading the failures
  • Server or client state saving, with numbers
  • Protected views stop GETs without a token
  • Making ViewExpiredException humane

2 runnable examples (Python, XML) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Exercise: predict eight requests, then check them Pro: opens with a Pro, Premium or Ultimate pass

Predicting the phases of a request before you send it is the quickest way to find a life-cycle bug. Fill in the table for eight requests to the registration form, then compare your answers with the recorded ones.

In this part:

  • Eight requests to predict
  • The recorded answers
  • What the answers show
  • Scoring your predictions: a rubric

1 runnable example (Python) · about 2 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

  1. Fresher · Warm-up

    Name the six phases of the Faces life cycle in order. Which of them does the first GET of a page run, and why?

    Restore View, Apply Request Values, Process Validations, Update Model Values, Invoke Application and Render Response. Restore View builds the component tree, or restores the saved one on a post; Apply Request Values gives each component its submitted text; Process Validations converts and validates it; Update Model Values copies the valid values into the beans; Invoke Application runs the action of the pressed button; Render Response writes the HTML and saves the view state. A first GET runs only Restore View and Render Response: nothing has been posted, so there is nothing to decode, validate or store, and after building a new tree Restore View sends the request straight to rendering. A phase listener registered for ANY_PHASE shows this order for any request.

  2. Fresher to mid

    On a form with a name and a semester, a user types a valid name and an out-of-range semester. After the error message, the debugger shows that the bean's name is still null, and a colleague files a bug against Faces. Explain what happened, and when it matters.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid

    A Cancel button has immediate="true", yet on one form pressing it shows "Value is required" next to a field. On the other forms it behaves. What do you look for, and how do you make Cancel reliable everywhere?

    Model answer, Pro. First step and follow-ups

  4. Mid to senior

    Users who leave a form open over lunch get an HTTP 500 page with ViewExpiredException when they press Save. Explain what happened, and compare the ways to fix it, with what each one costs.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Every request for a Faces page runs the same six phases in the same order; a first GET needs only Restore View and Render Response.
  • Validation failures jump from Process Validations to Render Response, so no value reaches the bean, not even the valid ones, and no action runs.
  • Setters run in Update Model Values and actions in Invoke Application; a phase listener with ANY_PHASE shows the order for any request.
  • immediate, the view state field, client-side state saving and protected views are the ways the order changes.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.