\n\n\n\n�JSF is like a power drill. It makes holes fast, but it will also make a hole in your desk if you let it.�
Why teams keep picking JSF
\n\n\n\nWhen folks ask me why JavaServer Faces keeps showing up on enterprise project plans, the answer is simple. Components. Managers like the promise of drag and drop screens. Developers like the idea of reusable widgets with validators, converters, and navigation built in. UI devs get Facelets templates and tag files. Ops teams get to run everything on Tomcat or GlassFish with out of the box support from the Java EE stack. It checks many boxes after a short demo.
\n\n\n\nThat demo is not a lie. With JSF 1.2 and Facelets, you can crank out forms, reuse layouts, and wire Ajax with RichFaces or ICEfaces. The moment you add real traffic, shared dev branches, and three releases running side by side, you discover the other side of the story. JSF is powerful, and power always comes with knobs. If no one owns the knobs, the app starts to feel sticky.
\n\n\n\nA week in the life of a JSF crew
\n\n\n\nDay one you sketch a flow in faces-config.xml, set up a couple of backing beans, and drop in Facelets templates. Day three you bring in Ajax4jsf and start partial updates. By Friday your signup flow works, validations fire, and QA is happy. Then the next sprint hits. Marketing wants a dashboard that refreshes parts of the page, ops wants lower memory on each node, and the team needs clean URLs for campaigns. The same framework that felt smooth now requires decisions about state saving, scope, and partial rendering.
\n\n\n\nThis is where teams either lean into the strengths of JSF or start fighting it. The trick is to know which levers matter and set a few ground rules that keep screens predictable.
\n\n\n\nDeep dive 1: State saving without surprises
\n\n\n\nJSF keeps a component tree for each view. That tree can live on the server or ride along the client. Default server side mode is safe, but it eats memory as your user count grows. Client side lowers memory but grows the page size and makes diffs noisy. Pick one and document why. If you go client side, turn on compression, and watch payloads.
\n\n\n\n<!-- web.xml -->\n<context-param>\n <param-name>javax.faces.STATE_SAVING_METHOD</param-name>\n <param-value>server</param-value> <!-- or client -->\n</context-param>\n\n<context-param>\n <param-name>com.sun.facelets.SKIP_COMMENTS</param-name>\n <param-value>true</param-value>\n</context-param>\n\n\n\nMemory also depends on scope. A bean in session feels convenient until you have thousands of users. Keep most beans in request or view scope. For view scope with JSF 1.2 and Facelets, many teams use a simple pattern with component bindings or a map inside the view root. If you are on Seam, you get a clean view scope but that is another topic.
\n\n\n\n<managed-bean>\n <managed-bean-name>signupBean</managed-bean-name>\n <managed-bean-class>com.example.SignupBean</managed-bean-class>\n <managed-bean-scope>request</managed-bean-scope>\n</managed-bean>\n\n\n\nTip: Profile memory with a real load. One user on a dev box will hide server side state problems. Open two browsers, fill a few forms, hit back, and watch session size.
\n\n\n\nDeep dive 2: Ajax with RichFaces and ICEfaces
\n\n\n\nPlain JSF does full page postbacks. That is fine for admin screens, not so great for dashboards. RichFaces gives you partial page rendering with a small tag set. ICEfaces pushes incremental updates with a slightly different model. Both work, but they shape how you code and test.
\n\n\n\n<!-- Facelets page using RichFaces -->\n<ui:composition xmlns="http://www.w3.org/1999/xhtml"\n xmlns:f="http://java.sun.com/jsf/core"\n xmlns:h="http://java.sun.com/jsf/html"\n xmlns:ui="http://java.sun.com/jsf/facelets"\n xmlns:a4j="http://richfaces.org/a4j"\n xmlns:rich="http://richfaces.org/rich">\n\n <h:form id="form">\n <h:panelGroup id="pricePanel">\n <h:outputText value="#{cartBean.total}"/>\n </h:panelGroup>\n\n <h:inputText value="#{cartBean.coupon}"/>\n <a4j:commandButton value="Apply"\n action="#{cartBean.applyCoupon}"\n reRender="pricePanel"\n oncomplete="console.log('updated')"/>\n </h:form>\n</ui:composition>\n\n\n\nKeep partial updates tight. Re render the smallest area you can. Avoid nesting many forms. Watch for duplicate component ids when you include fragments. If tests start failing only on Fridays, look for Ajax areas that rerender a parent component. That can reset child state and confuse users.
\n\n\n\nPick one Ajax library for the app. Mixing RichFaces and ICEfaces in the same page gets messy. Both touch the request and response in special ways. Your future self will thank you for a single approach.
\n\n\n\nDeep dive 3: Validation, conversion, and messages that help
\n\n\n\nJSF validators and converters are a sweet spot. They live with the component, they run before your action method, and they keep the code honest. The miss is usually in the messages. Users do not enjoy stack traces in a growl panel.
\n\n\n\n<h:form>\n <h:messages errorClass="err" infoClass="ok"/>\n\n <h:inputText id="email" value="#{userBean.email}">\n <f:validator validatorId="emailValidator"/>\n </h:inputText>\n\n <h:commandButton value="Create" action="#{userBean.create}"/>\n</h:form>\n\n\n\n// EmailValidator.java\n@FacesValidator("emailValidator")\npublic class EmailValidator implements Validator {\n public void validate(FacesContext ctx, UIComponent c, Object value) throws ValidatorException {\n String s = value == null ? "" : value.toString();\n if (!s.matches(".+@.+\\\\..+")) {\n FacesMessage m = new FacesMessage("Please enter a valid email");\n m.setSeverity(FacesMessage.SEVERITY_ERROR);\n throw new ValidatorException(m);\n }\n }\n}\n\n\n\nKeep messages in a bundle and reference it in faces config so your UI team can tune the tone without touching code.
\n\n\n\n<!-- faces-config.xml -->\n<application>\n <message-bundle>com.example.messages</message-bundle>\n</application>\n\n\n\nBonus: Wrap common patterns into small composite tags with Facelets tag files. A field with label input help and message can be one tag. That removes copy paste bugs across forms.
\n\n\n\nPractical setup that keeps teams happy
\n\n\n\nUse Facelets for everything. JSP works but template reuse is nicer with Facelets. Pair JSF with Spring for services and data access and wire beans through EL resolvers. Keep navigation simple. Most screens can use postback to the same view and outcome based buttons for branching.
\n\n\n\n<!-- faces-config.xml navigation -->\n<navigation-rule>\n <from-view-id>/signup.xhtml</from-view-id>\n <navigation-case>\n <from-outcome>success</from-outcome>\n <to-view-id>/welcome.xhtml</to-view-id>\n <redirect />\n </navigation-case>\n</navigation-rule>\n\n\n\nOn the tool side, NetBeans 6.1 and Eclipse Ganymede both offer decent JSF support. The Facelets plugin is worth the install if you live in Eclipse. For servers, GlassFish v2 has smooth JSF and Facelets support, and Tomcat 6 is fine for lighter stacks.
\n\n\n\nDo not skip filters. Add a character encoding filter and set everything to UTF 8. Broken accents in user names can ruin a launch day.
\n\n\n\n<filter>\n <filter-name>encodingFilter</filter-name>\n <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>\n <init-param>\n <param-name>charset</param-name>\n <param-value>UTF-8</param-value>\n </init-param>\n</filter>\n<filter-mapping>\n <filter-name>encodingFilter</filter-name>\n <url-pattern>/*</url-pattern>\n</filter-mapping>\n\n\n\nWhat JSF teaches you even if you move on later
\n\n\n\nJSF is opinionated about state, events, and components. That mental model sticks with you. You start to think in trees, scopes, and clean boundaries between view and action. You learn to respect page size, and you learn that a nice component can hide a heavy cost. These are lessons that apply whether next month you touch Flex, GWT, or something lighter.
\n\n\n\nSo is JSF right for every team right now. Not really. If you need a tiny public site, keep it simple. If you are building form heavy apps with lots of reuse and a team that will share components, JSF with Facelets is a strong pick. Go in with eyes open, set your knobs early, and write down the rules. The power is real. The caveats are too.
\n\n\n\nCreated on 2008 07 12
\n