• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
JavaServer Faces Anti-Patterns and Pitfalls
 

JavaServer Faces Anti-Patterns and Pitfalls

on

  • 3,849 views

Here are my slides from ApacheCon 2007

Here are my slides from ApacheCon 2007

Statistics

Views

Total Views
3,849
Views on SlideShare
3,841
Embed Views
8

Actions

Likes
3
Downloads
91
Comments
0

4 Embeds 8

https://www.linkedin.com 3
http://www.slideshare.net 2
http://www.linkedin.com 2
http://localhost 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    JavaServer Faces Anti-Patterns and Pitfalls JavaServer Faces Anti-Patterns and Pitfalls Presentation Transcript

    • JavaServer Faces Anti-Patterns Dennis Byrne - ThoughtWorks [email_address] http://notdennisbyrne.blogspot.com
    • 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>
    • 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(&quot;start&quot;);
      • if(end == null)
      • throw new NullPointerException(&quot;end&quot;);
      • if(start.after(end))
      • throw new IllegalStateException(&quot;start > end&quot;);
      • }
      • }
    • 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 ...
      • }
      • }
    • 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; }
      • }
    • 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>
    • 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>
    • 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
    • Thread Safety
      • <h:inputText value=&quot;#{managedBean.value}&quot; converter=&quot;#{threadUnsafe}&quot; />
      • <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=&quot;#{managedBean.value}&quot; >
      • <f:converter converterId=&quot;threadUnsafe&quot; > <!-- Always Safe -->
      • </h:inputText>
      • <converter>
      • <converter-id>threadUnsafe</converter-id>
      • <converter-class>org.apache.myfaces.book.ThreadUnsafeConverter
      • </converter-class>
      • </converter>
    • Facelets Migration
      • public class WidgetTag extends UIComponentELTag{
      • private String title, styleClass = &quot;default_class&quot;;
      • protected void setProperties(UIComponent component) {
      • super.setProperties(component);
      • Widget span = (Widget) component;
      • span.setStyleClass(styleClass);
      • span.setTitle(title == null ? &quot;no title&quot; : title);
      • FacesContext ctx = FacesContext.getCurrentInstance();
      • Map session = ctx.getExternalContext().getSessionMap();
      • span.setStyle((String) session.get(&quot;style&quot;));
      • }
      • }
    • 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}
    • 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);
        • }
      • }
    • 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);
      • }
      • }
    • Portlet ClassCastException
      • FacesContext ctx = FacesContext.getCurrentInstance();
      • ExternalContext ectx = ctx.getExternalContext();
      • ServletRequest request = ( ServletRequest )ectx .getRequest();
      • String id = request.getParameter(&quot;id&quot;);
      • FacesContext ctx = FacesContext.getCurrentInstance();
      • ExternalContext ectx = ctx.getExternalContext();
      • String id = ectx.getRequestParameterMap().get(&quot;id&quot;);
    • 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 */
        • }
        • }
        • }
    • N + 1
        • <!-- One trip to the database for the master record ... -->
        • <h:dataTable value=&quot;#{projectBean.projects}&quot; var=&quot;project&quot;>
        • <h:column>
        • <h:commandLink action=&quot;#{projectBean.viewProject}&quot;
        • value=&quot;view project&quot;/>
        • </h:column>
        • <h:column>
        • <!-- ... and + N trips for each child record -->
        • <f:facet name=&quot;header&quot;>Project Manager</f:facet>
        • #{project .manager.name }
        • </h:column>
        • <h:column>
        • <f:facet name=&quot;header&quot;>Project Name</f:facet>
        • #{project.name}
        • </h:column>
        • </h:dataTable>
    • N + 1- N
      • public class OpenTransactionInApplicationPhaseListener
      • implements PhaseListener {
      • public void beforePhase(PhaseEvent event) {
      • try {
      • ObjectRelationalUtility.startTransaction();
      • } catch (Throwable throwable) { /* sans error handling */ }
      • }
      • public void afterPhase(PhaseEvent event) {
      • try {
      • ObjectRelationalUtility.commitTransaction();
      • } catch (Throwable throwable) {
      • ObjectRelationalUtility.rollbackTransaction();
      • }
      • }
      • public PhaseId getPhaseId(){return PhaseId.INVOKE_APPLICATION ;}
      • }
    • Thanks
      • Dennis Byrne - ThoughtWorks
      • [email_address]
      • http://notdennisbyrne.blogspot.com