tags:

views:

213

answers:

3

Assuming I have a list of Animal(s) with standard polymorphic behavior like Cat(s) and Dog(s).

What is the best approach to display a different JSP view for each one in the list?

<c:forEach var='animal' items='${animals}'>
 //show a different template per animal type
</c:forEach>

To be honest having a #toJSP for each bean is something I wouldn't consider for obvious reasons.

I am tempted however of using a

public interface Template{

  public String render()
}

with each Animal passed in the constructor, however I'm not sure where these objects should be created. I guess it can be done inside the JSP in a <%%> but I'm hesitant using this notation for some reason.

So I ended up using the "bundles" that are available for i18n in JSP in the following way

<fmt:message var="template" key="${animal.class.name}" />

with a template.properties file

foo.bar.Animal = animal.jsp 
foo.bar.Cat = cat.jsp
foo.bar.Dog = dog.jsp

So the final solution would look like this

<c:forEach var='animal' items='${animals}'>
 <span>
  <c:set var="animal" scope="request" value="${animal}"/>
  <fmt:message var="template" key="${animal.class.name}" />
  <jsp:include page="${template}" />
 </span>
</c:forEach>

With template files that looks like this

Hello animal ${animal}!
Hello cat ${animal}!
Hello dog ${animal}!
A: 

Declare an abstract method on Animal that returns a string, called getMyJspPage().

Then cats and dogs can return a reference to a different jsp page or jsp fragment that you can include.

Michael Sharek
A: 

You could use a custom tag that takes the current animal as an attribute and uses it to determine the correct view

Chris R
+1  A: 

Unfortunately, inheritance and polymorphism doesnt work in jsps very well.

The easiest, and most maintainable solution has been to just do a lot of

<c:choose>
   <c:when test="${animal.type == 'Cat'}">
      <my:renderCat cat="${animal}"/>
   </c:when>
   <c:when test="${animal.type == 'Dog'}">
      <my:renderDog Dog="${animal}"/>
   </c:when>
   ...
</c:choose>

and have tag files (like renderDog.tag, renderCat.tag) that takes each specific animal as an attribute, and call out to them. at least it keeps the dispatching, and the rendering seperated.

Chii