Java Server Faces Antipatterns and Best Practices Kito
Java. Server Faces Antipatterns and Best Practices Kito D. Mann Principal Consultant
Kito D. Mann www. twitter. com/kito 99 » Principal Consultant at Virtua » http: //www. virtua. com » Training, consulting, architecture, mentoring, » JSF product development » Author, Java. Server Faces in Action » Founder, JSF Central » http: //www. jsfcentral. com » Internationally recognized speaker » Java. One, Java. Zone, Devoxx, NFJS, TSSJS, etc. Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Kito D. Mann www. twitter. com/kito 99 » JCP Member » JSF, Web. Beans, JSF Portlet Bridge, Portlets Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Avoid the Big Ball of Mud » http: //www. laputan. org/mud/ Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
ANTIPATTERNS Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » Several hundred or thousand lines Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » Several hundred or thousand lines » Unnecessary comments Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » Several hundred or thousand lines » Unnecessary comments » Very complicated view that uses Ajax Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » » Several hundred or thousand lines Unnecessary comments Very complicated view that uses Ajax Business logic in backing beans Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » » » Several hundred or thousand lines Unnecessary comments Very complicated view that uses Ajax Business logic in backing beans Data access logic in backing beans Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant backing bean » Refactor » Multiple backing beans » Move code » Other layers » Utility classes » Other scoped objects Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean subclasses domain object Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean subclasses domain object » Violates separation of concerns and OO principles Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean subclasses domain object » Violates separation of concerns and OO principles Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Flat backing bean hierarchy Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Flat backing bean hierarchy Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
public void validate. Name (Faces. Context faces. Context, UIComponent sender, Object new. Value) throws Validator. Exception { if (!name. Exists((String) new. Value)) { faces. Context. add. Message("new. Widget. Form: name", new Faces. Message("Duplicate widget name")); } } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
public void validate. Name (Faces. Context faces. Context, UIComponent sender, Object new. Value) throws Validator. Exception { if (!name. Exists((String) new. Value)) { faces. Context. add. Message("new. Widget. Form: name", new Faces. Message("Duplicate widget name")); } } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies public void validate. Name (Faces. Context faces. Context, UIComponent sender, Object new. Value) throws Validator. Exception { if (!name. Exists((String) new. Value)) { faces. Context. add. Message("new. Widget. Form: name", new Faces. Message("Duplicate widget name")); } } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies public void validate. Name(Faces. Context faces. Context, UIComponent sender, Object new. Value) throws Validator. Exception { if (!name. Exists((String) new. Value)) { throw new Validator. Exception(new Faces. Message( "Duplicate widget name. ")); } } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies public void delete. Widget (Action. Event event) { Faces. Context faces. Context = Faces. Context. get. Current. Instance(); String id = event. get. Component(). get. Client. Id(faces. Context); int begin. Index = id. index. Of(": ", 0); begin. Index = id. index. Of(": ", begin. Index + 1); int end. Index = id. index. Of(": ", begin. Index + 1); String row. Index = id. substring(begin. Index + 1, end. Index); delete. Widget(Integer. parse. Int(row. Index)); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies public void delete. Widget (Action. Event event) { Faces. Context faces. Context = Faces. Context. get. Current. Instance(); String id = event. get. Component(). get. Client. Id(faces. Context); int begin. Index = id. index. Of(": ", 0); begin. Index = id. index. Of(": ", begin. Index + 1); int end. Index = id. index. Of(": ", begin. Index + 1); String row. Index = id. substring(begin. Index + 1, end. Index); delete. Widget(Integer. parse. Int(row. Index)); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies <h: data. Table id="widget. Table" value="#{widget. Editor. Controller. widgets}" var="widget"> <h: column> <f: facet name="header">Name</f: facet> <h: output. Text value="#{widget. name}" /> </h: column> <f: facet name="header">Size</f: facet> <h: output. Text value="#{widget. size}" /> </h: column> <h: column> <h: command. Link value="#{widget. Editor. Controller. delete}"> <f: set. Property. Action. Listener value="widget" target="#{widget. Editor. Controller. current. Widget}"/> </h: command. Link> </h: column> </h: data. Table> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies <h: data. Table id="widget. Table" value="#{widget. Editor. Controller. widgets}" var="widget"> <h: column> <f: facet name="header">Name</f: facet> <h: output. Text value="#{widget. name}" /> </h: column> <f: facet name="header">Size</f: facet> <h: output. Text value="#{widget. size}" /> </h: column> <h: command. Link value="#{widget. Editor. Controller. delete(widget)}"/> </h: column> </h: data. Table> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies » Use value or component bindings Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Magic string dependencies » Use value or component bindings » Retrieve the sending UI component in event listener methods Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary Faces. Context lookups Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary Faces. Context lookups » Calling Faces. Context. get. Current. Instance() multiple times in the same method Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary Faces. Context lookups » Use a variable Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Interdependent backing beans Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Interdependent backing beans » Factor out behavior to other layers or helper objects » Inject the dependency Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Interdependent backing beans Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view » Similar markup repeated in every page Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view » Similar markup repeated in every page » No templating or reuse Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view » Use templating or includes for any common markup Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view » Use templating or includes for any common markup » Break up pages into smaller fragments Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Giant view » Use templating or includes for any common markup » Break up pages into smaller fragments » Use composite components Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Bloated component tree Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Bloated component tree » Consume lots of memory » Render large pages » Slower Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Bloated component tree » The rendered attribute does not affect the size of the component tree Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Bloated component tree » Is Ajax really required? » Consider transient markup (<div>, <span>, text output, etc. ) » Consider stateless views (JSF 2. 2) » Investigate dynamic loading features Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Bloated component tree » Use a scope other than session » Use <c: if> (sparingly) » Split into separate views Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
public List<Widget> get. Widgets () { Widget. Provider widget. Provider = new Widget. Provider(); return widget. Provider. get. Widgets(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
public List<User> get. Users () { ELContext el. Context = Faces. Context. get. Current. Instance(). get. ELContext(); User. Provider user. Provider = (User. Provider) el. Context. get. ELResolver() . get. Value(el. Context, null, "user. Provider"); return user. Provider. get. Users(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lack of dependency injection public List<User> get. Users () { ELContext el. Context = Faces. Context. get. Current. Instance(). get. ELContext(); User. Provider user. Provider = (User. Provider) el. Context. get. ELResolver() . get. Value(el. Context, null, "user. Provider"); return user. Provider. get. Users(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lack of dependency injection » Don't create singletons or scoped objects with new operator » Use dependency injection to wire up backing beans to other objects Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lack of dependency injection @Inject private User. Provider user. Provider; public User. Provider get. User. Provider() { return user. Provider; } public void set. User. Provider(User. Provider user. Provider) { this. user. Provider = user. Provider; } public List<User> get. Users() { return user. Provider. get. Users(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
public void get. Data() { return service. get. Data(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Getter grabber public void get. Data() { return service. get. Data(); } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Getter grabber » Do not perform any expensive operations in getters » Retrieve data when view is loaded Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
» widget. Viewer. xhtml » Widget. Editor. Page. xhtml » wiget_search. xtml Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Inconsistent artifact names » widget. Viewer. xhtml » Widget. Editor. Page. xhtml » wiget_search. xtml Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Inconsistent artifact names » Define and enforce naming conventions Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Initializing backing beans in constructor » Dependency injection has not taken place Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Initializing backing beans in constructor » Lazy initialization » Use @Post. Construct annotation » Initialize before the view is displayed » JSF 1. 2: Phase. Listener » <f: view before. Phase="#{my. Bean. init}"> » JSF 2: Before. Render event » <f: event type="before. Render" listener="#{my. Bean. init}"> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Eager view initialization Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Eager view initialization » Lazy initialization Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lazy library initialization Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lazy library initialization » Causes unnecessary delays for the first user Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Lazy library initialization » Initialize expensive objects at startup » Spring Context. Loader » JSF 1. x: Servlet. Context. Listener » JSF 2: Load managed bean at startup (eager) with @Post. Construct Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Static variables in scoped objects Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Static variables in scoped objects » Breaks the semantics of scoped state » Can cause synchronization issues » Does not work in a clustered environment Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Static variables in scoped objects » Use an application-scoped object or a constant Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Non-serializable session-scoped objects » Make all session, view and conversationscoped objects serializable Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Overcomplicated expressions Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Overcomplicated expressions » Hard to read » Mixes business logic with display logic Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Overcomplicated expressions » Move logic into backing bean properties Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Exception eating public List<User> get. Users () { try { return user. Provider. get. Users(); } catch (Data. Access. Exception e) { e. print. Stack. Trace(); } return null; } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Exception eating » If you cannot properly handle the exception, don't » Let exceptions bubble up to the container » Make sure you use a Logger instead of System. out. println() » Use the JSF 2 Exception. Handler to centralize exception handling Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary UI Component Bindings Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary UI Component Bindings » Component bindings can be problematic for non-request scoped beans » http: //leadingyouastray. blogspot. com/2010/02/re ferences-to-uicomponents-in-session. html » Component bindings in view-scoped backing beans break partial state saving (fixed in JSF 2. 2) Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Unnecessary UI Component Bindings » Use value bindings » <f: set. Property. Action. Listener> » Retrieve components from event objects in event listeners » Use request-scoped holder pattern Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean messages Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean messages » Use ordinary JSF messages Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean messages » Use ordinary JSF messages » Create convenience methods in your base backing bean class Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Backing bean messages » Use ordinary JSF messages » Create convenience methods in your base backing bean class » Issue: scope » Will redisplay for request scoped beans unless you do a redirect (fixed in JSF 2. 0) Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Immediate overuse Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Immediate overuse » Avoid using immediate for non-Command components Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Immediate overuse » Avoid using immediate for non-Command components » Consider putting input controls in a separate form Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Immediate overuse » Avoid using immediate for non-Command components » Consider putting input controls in a separate form » Use Ajax features » Rich. Faces: <a 4 j: ajax. Only> » JSF 2: <f: ajax. . . execute="@this"/> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Nameless UI components <h: form> <h: input. Text value="#{widget. Editor. current. Widget}" /> <h: command. Button value="Submit” action="#{widget. Editor. save}" /> </h: form> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Nameless UI components » Makes testing difficult » Hard to integrate with custom Java. Script or Ajax features » Increases rendered page size Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
<h: form id="frm"> <h: input. Text id="name" value="#{widget. Editor. current. Widget}" /> <h: command. Button id="submit" value="Submit” action="#{widget. Editor. save}" /> </h: form> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Nameless UI components » Assign short, meaningful ids » All input controls » Components with Ajax behavior » Naming containers Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Nameless UI components » Develop naming conventions » frm » dtb » widget. Frm » widget. Dtb Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
CSS style soup » Hardcoded styles in JSF views Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
CSS style soup » Use CSS selectors instead of inline styles » Most suites let you override default selectors » Develop custom theme if possible Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Session overload Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Session overload » Put beans in request scope when possible » For Ajax, use view scope » JSF 1. x: not supported » Seam Page scope » Tomahawk <t: save. State> » Rich. Faces <a 4 j: keep. Alive> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Session overload » Conversation scope » Not implemented natively » JSF 1. x » Seam, My. Faces Orchestra » My. Faces Trinidad Page. Flow. Scope » Spring Web Flow » Spring 3. 1 » JSF 2: CDI Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
GOTCHAS Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Null input values » JSF 1. 2: Null values are converted to a 0 or false » https: //jsp-specpublic. dev. java. net/issues/show_bug. cgi? id=183 » Tomcat and JBoss » "-Dorg. apache. el. parser. COERCE_TO_ZERO=false" as a VM parameter. » JSF 2: javax. faces. INTERPRET_EMPTY_STRING_SUB MITTED_VALUES_AS_NULL context parameter Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Null input values » JSF 2: javax. faces. INTERPRET_EMPTY_STRING_SUB MITTED_VALUES_AS_NULL context parameter Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Validating empty fields » JSF 1. x: Validators not called for empty values » JSF 2: javax. faces. VALIDATE_EMPTY_FIELDS context parameter Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
BEST PRACTICES Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Use constants or enums for action method outcomes public enum Outcome { SUCCESS, FAILURE, PREVIOUS, NEXT, ERROR; @Override public String to. String() { return super. to. String(). to. Lower. Case(); } } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Use constants or enums for action method outcomes public Outcome update. Widget() {. . return Outcome. SUCCESS; } Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Build a library of composite components » Standardize behavior and look and feel Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Build a library of composite components » Standardize behavior and look and feel » Examples » Input control layout » Panels » Buttons » Icons » Forms Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Build a library of composite components <html xmlns="http: //www. w 3. org/1999/xhtml" xmlns: h="http: //java. sun. com/jsf/html" xmlns: composite="http: //java. sun. com/jsf/composite"> <composite: interface> <composite: attribute name="label" /> <composite: attribute name="value" required="true" /> </composite: interface> <composite: implementation> <h: output. Label for="input" value="#{cc. attrs. label}" /> <h: input. Text id="input" value="#{cc. attrs. value}" /> </composite: implementation> </html> Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Development team best practices » Documentation » Coding guidelines » Code review » Static analysis » Build process » Continuous integration » Unit testing Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
More Best Practices » Externalize all messages to resource bundles » Use another object for state in Phase. Listeners Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
R Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
RT Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
RTF Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
RTFM Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
Resources » http: //www. javaserverfaces. org » http: //www. jsfcentral. com » Books » Core JSF » JSF: The Complete Reference Copyright (C) 2010 -14 Virtua, Inc. All rights reserved.
- Slides: 114