JavaServer Faces Anti-Patterns and Pitfalls
Upcoming SlideShare
Loading in...5
×
 

JavaServer Faces Anti-Patterns and Pitfalls

on

  • 4,011 views

Here are my slides from ApacheCon 2007

Here are my slides from ApacheCon 2007

Statistics

Views

Total Views
4,011
Views on SlideShare
4,003
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