1 / 17

JavaServer Faces Anti-Patterns

Learn about common mistakes in JavaServer Faces like use of invalid setters and find solutions to implement proper validation.

richellej
Download Presentation

JavaServer Faces Anti-Patterns

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. JavaServer Faces Anti-Patterns Dennis Byrne - ThoughtWorks dennisbyrne@apache.org

  2. Validating Setter <managed-bean> <managed-bean-name>iterationBean</managed-bean-name> <managed-bean-class>com.thoughtworks.Iteration </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>start</property-name> <value>#{sprintBean.currentStart}</value> </managed-property> <managed-property> <property-name>end</property-name> <value>#{sprintBean.currentEnd}</value> </managed-property> <managed-property> <property-name>last</property-name> <value>hack</value> </managed-property> </managed-bean>

  3. Validating Setter public class Iteration { private Calendar start, end; // injected // sans setters and getters for start, end public void setLast(String last) { if(start == null) throw new NullPointerException("start"); if(end == null) throw new NullPointerException("end"); if(start.after(end)) throw new IllegalStateException("start > end"); } }

  4. Validating Setter Solutions <application> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> </application> <application><el-resolver> org.apache.myfaces.el.unified.resolver.GuiceResolver </el-resolver> </application> public class Iteration { private Calendar start, end; // injected @PostConstruct public void initialize() { // domain validation logic here ... } }

  5. The Map Trick #{requestScopedMap.key} // calls get(‘key’) #{requestScopedMap[‘key’]} public class MapTrick implements java.util.Map { public Object get(Object key) { return new BusinessLogic().doSomething(key); } public void clear() { } public boolean containsKey(Object arg) { return false; } public boolean isEmpty() { return false; } public Set keySet() { return null; } public Object put(Object key, Object value) { return null; } public void putAll(Map arg) { } public Object remove(Object arg) { return null; } public int size() { return 0; } }

  6. déjà vu PhaseListener <context-param> <description> comma separated list of JSF conf files </description> <param-name>javax.faces.CONFIG_FILES</param-name> <param-value> /WEB-INF/faces-config.xml </param-value> </context-param> <lifecycle> <phase-listener> com.thoughtworks.PhaseListenerImpl </phase-listener> </lifecycle>

  7. XML Hell <navigation-rule><from-view-id>/home.xhtml</from-view-id> <navigation-case> <from-outcome>contact_us</from-outcome> <to-view-id>/contact.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule><from-view-id>/site_map.xhtml</from-view-id> <navigation-case> <from-outcome>contact_us</from-outcome> <to-view-id>/contact.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule><from-view-id>*</from-view-id> <navigation-case> <!-- global nav rule --> <from-outcome>contact_us</from-outcome> <to-view-id>/contact.xhtml</to-view-id> </navigation-case> </navigation-rule>

  8. Thread Safety • javax.faces.event.PhaseListener • javax.faces.render.Renderer • Managed Beans • javax.faces.convert.Converter • javax.faces.validator.Validator • javax.faces.FacesContext • JSF Tags

  9. Thread Safety <h:inputText value="#{managedBean.value}" converter="#{threadUnsafe}" /> <managed-bean> <managed-bean-name>threadUnsafe</managed-bean-name> <managed-bean-class> org.apache.myfaces.book.ThreadUnsafeConverter </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <h:inputText value="#{managedBean.value}" > <f:converter converterId="threadUnsafe" > <!-- Always Safe --> </h:inputText> <converter> <converter-id>threadUnsafe</converter-id> <converter-class>org.apache.myfaces.book.ThreadUnsafeConverter </converter-class> </converter>

  10. Facelets Migration public class WidgetTag extends UIComponentELTag{ private String title, styleClass = "default_class"; protected void setProperties(UIComponent component) { super.setProperties(component); Widget span = (Widget) component; span.setStyleClass(styleClass); span.setTitle(title == null ? "no title" : title); FacesContext ctx = FacesContext.getCurrentInstance(); Map session = ctx.getExternalContext().getSessionMap(); span.setStyle((String) session.get("style")); } }

  11. Law of Demeter • A “Train Wreck” - sensitive to changes in domain model employee.getDepartment().getManager() .getOffice().getAddress().getZip(); • An EL “Train Wreck” - sensitive to changes in domain model #{employee.department.manager.office.address.zip} • Encapsulated, insensitive to changes in domain model #{employee.officeManagersZipCode}

  12. Vendor Lock-in import org.apache.myfaces.component.html.ext.HtmlInputHidden; import org.apache.myfaces.component.html.ext.HtmlInputText; import org.apache.myfaces.component.html.ext.HtmlOutputText; public class ImplementationDependentManagedBean { private HtmlInputText input ; private HtmlInputHidden hidden ; private HtmlOutputText output ; /* getters and setters omitted */ public boolean recordTotal(ActionEvent event) { long total = ((Long)input.getValue()).longValue(); total += ((Long)hidden.getValue()).longValue(); total += ((Long)output.getValue()).longValue(); return new JmsUtil().broadcastTotal(total); } }

  13. Vendor Lock-in Solution import javax.faces.component.ValueHolder; public class RefactoredManagedBean { private ValueHolder input ; private ValueHolder hidden ; private ValueHolder output ; /* getters & setters ommitted */ public boolean recordTotal(ActionEvent event) { long total = 0; ValueHolder[] vh = new ValueHolder[] {input, hidden, output}; for(ValueHolder valued : vh) total += ((Long)valued.getValue()).longValue(); return new JmsUtil().broadcastTotal(total); } }

  14. Portlet ClassCastException FacesContext ctx = FacesContext.getCurrentInstance(); ExternalContext ectx = ctx.getExternalContext(); ServletRequest request = (ServletRequest)ectx .getRequest(); String id = request.getParameter("id"); FacesContext ctx = FacesContext.getCurrentInstance(); ExternalContext ectx = ctx.getExternalContext(); String id = ectx.getRequestParameterMap().get("id");

  15. OpenTransactionInViewFilter public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){ try { ObjectRelationalUtility.startTransaction(); chain.doFilter(request, response); ObjectRelationalUtility.commitTransaction(); } catch (Throwable throwable) { try { ObjectRelationalUtility.rollbackTransaction(); } catch (Throwable _throwable) { /* sans error handling */ } } }

  16. N + 1 <!-- One trip to the database for the master record ... --> <h:dataTable value="#{projectBean.projects}" var="project"> <h:column> <h:commandLink action="#{projectBean.viewProject}" value="view project"/> </h:column> <h:column> <!-- ... and + N trips for each child record --> <f:facet name="header">Project Manager</f:facet> #{project.manager.name} </h:column> <h:column> <f:facet name="header">Project Name</f:facet> #{project.name} </h:column> </h:dataTable>

  17. N + 1- N public class OpenTransactionInApplicationPhaseListener implements PhaseListener { public void afterPhase(PhaseEvent event) { try { ObjectRelationalUtility.startTransaction(); } catch (Throwable throwable) { /* sans error handling */ } } public void beforePhase(PhaseEvent event) { try { ObjectRelationalUtility.commitTransaction(); } catch (Throwable throwable) { ObjectRelationalUtility.rollbackTransaction(); } } public PhaseId getPhaseId(){return PhaseId.INVOKE_APPLICATION;} }

More Related