Ant, JspC, and Other Horrors. 46

Posted by Uncle Bob Sat, 03 Feb 2007 21:30:28 GMT

I’ve been trying to precompile JSPs today. They reference custom tag libraries. What a joy…

You’d think it would be simple to translate JSP file into Java. Tomcat does it all the time, automatically.

I’d very much like to precompile my JSP files, because I want to write tests for them; and I don’t want to use Cactus, or have the server up for my tests.

I found the Jasper compiler, and the ant task that invokes it, but I thought it might be nice to run it from the command line just to see how it work. You know:
java org.apache.jasper.JspC myFile.jsp
You’d think that would be easy, wouldn’t you?

But NO. You have to include a zillion jars just to get the JspC compiler to run. Jars from apache.common, and appache.server, and commons.logging, etc. You even have to include the ant.jar file.

I consider that last to be completely sick. What the H___ does JspC have to do with Ant? Why in the begrosian devalent is there a dependency on ant, of all things??!!? Haven’t these people heard of Dependency Management?

sigh

Anyway, I gave up on the command line idea because apparently the Jasper compiler wants to see the web.xml file and so the whole web app has to be put together before you can run the compiler. I understand why they did this, but it sure is frustrating for someone who just wants to run the frickin compiler.

So I fell back on the ant task. Now I have to tell you that I hate ant. Ant was born during those sick sick days when people thought that XML was a cool grammar. XML is not a cool grammar. XML is a markup language. It works fine to encode data that machines can read, and humans can barely read, but it is by no means a natural syntax. Ant suffers from terrible keyword-itis, and the nasty inflexibility.

Inflexible you say? Why, can’t you write any ant-task you please?

Sure, so what. You think I want to read a bunch of java code to figure out how to invoke the JspC command line? Hell, all I want to do is compile one frickin JSP file into a JAVA file. If ant let me pass in command lines, like make or rake or some other reasonable build tool, I just might be able to do that.

But NO. The JspC ant task wants to compile the WHOLE web app for me. And it wants there to be a web.xml file that describes that web app.

sigh

So, like a good little ant slave, I put the ant build script for JspC into my build.xml file and fired it up. It took a little fiddling and cajoling. But eventually I got the JspC compiler to run. And what did it say?

/Users/unclebob/projects/Library/Library/build.xml:147: org.apache.jasper.JasperException: file:/Users/unclebob/projects/Library/Library/web/WEB-INF/pages/template.jsp(25,21) Unable to load tag handler class "com.objectmentor.library.web.framework.tags.ActionPathTag" for tag "library:actionPath"

(what is it about error messages nowadays that they have to be 253 characters in length? Why can’t we have nice little error messages?)

The problem is that the JSP file that I am trying to compile is using a custom tag, and apparently there is no way to get the JspC ant task to tell the JspC compiler the classpath of my tag handler. I’ve tried everything I could think of, and searched high and low on the net, but I can’t seem to figure out how to make this work.

So I’m done for the weekend. I was hoping to write a blog on testing JSPs this weekend while attending my son’s wrestling match (he’s likely to make it to state this year), but it’ll have to wait because there’s no internet at the match.

I guess I’ll play with Ruby instead.

UPDATE

While eating dinner, it hit me. If I set the CLASSPATH variable to include the jar with the tag in it, and if I invoke JspC from the command line (or with a java ant task) it might work. So I tried it, and…whaddyano? it worked just fine.

Here is the ant target I eventually used. Note the hideous dependencies required by JspC. You might find this target useful if you ever want to precompile jsps that use custom tags.

  <target name="jsp" depends="jar">
    <delete dir="${basedir}/test/testjsp"/>
    <java classname="org.apache.jasper.JspC" fork="true">
      <arg line="-d ${basedir}/test/testjsp -p com.objectmentor.library.testjsp -webapp ${web.home}"/>
      <classpath>
        <fileset dir="${catalina.home}/common/lib">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${catalina.home}/server/lib">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="${catalina.home}/bin">
          <include name="*.jar"/>
        </fileset>
        <pathelement location="/Developer/Java/Ant/lib/ant.jar"/>
        <pathelement location="${build.jar.home}/library-framework.jar"/>        
      </classpath>
    </java>
  </target>

Now on to the wrestling match!

Not so fast.

Some of the java files generated from the JSPs don’t compile. There is some mismatch between the tag processing libraries or something. The generated code is hideous to read, and the problem is probably subtle. So I’m going to go to bed.

urg!.

WRESTLING and SUCCESS

So, here I am at the wrestling match. The thing about these matches is that I need to pay attention for about 6 minutes every two hours. That’s how often Justin wrestles. So, of course, I bring my laptop and sit on the bleachers working on code while the whistles are blowing and the parents are screeching and my butt slowly gets numb.

Justin won his first match. It was a slaughter. He’s strong and smart, and has a good chance to get into the state tournament.

I won my first match with JSP too. Apparently the compile environment of my IDE is not exactly the same as the compile environment that Jasper uses. But I was able to resolve that by simply setting the -compile switch on the JspC command line. This compiles the generate java files in place using what seems to be the correct compile environment. At least there are no compiler errors.

I also set the -mapped command line argument. This causes jasper to create a new Out(...) call for each line on the input jsp. This makes the java file a bit easier to read. Apparently this command line is set when tomcat automatically compiles the jsps, and so comparing my generated files and tomcats generated files is easier with this argument set.

I set up a simple unit test to see if I could create an instance of one of the generated servlets. It looks like this:
public class ManageJspTest extends TestCase {
  public void testCreate() throws Exception {
    HttpJspBase manage = new com.objectmentor.library.jsp.WEB_002dINF.pages.books.manage_jsp();
  }
}

At first this didn’t compile because the servlet apparently uses the apache.commons.logging. stuff. So I had to put that in the classpath of the unit tests. Grumble! “Dependency management guys! Dependency Management. Why do my unit tests need to know about logging? sigh

Anyway: I can now compile a unit test that creates a servlet generated by Jasper!!!

This is very good news. I have my doubts about whether it will work however. The code generated by my ant script, and the code generated by tomcat are not exact matches. There is one segment that is markedly different. The following snippet is in the tomcat generated java file, but not in the ant-script generated java file.
  static {
    _jspx_dependants = new java.util.ArrayList(1);
    _jspx_dependants.add("/WEB-INF/tld/LibraryTags.tld");
  }
I don’t understand exactly why, but I think it must have something to do with a difference in the way the two environments view the tag libraries.

Anyway, I imagine that when I try to execute the servlets generated by the ant script, they will fail because this code is missing.

Anyway, I think I’ll go watch Justin wrestle some more.


Justin won his second match at Regionals. That put’s him in the finals for the tournament, and ensures that he has a spot in the Sectionals next week.


Justin doesn’t wrestle again until 4pm, so Ann Marie and I went home for a couple of hours. While there, I was able to set up a quick test to invoke the generated servlet. It looks like this:
public class ManageJspTest extends TestCase {
  private MockPageContext pageContext;
  private MockJspWriter jspWriter;
  private JspFactory mockFactory;

  public void testCreate() throws Exception {
    jspWriter = new MockJspWriter(10000, false);
    pageContext = new MockPageContext(jspWriter);
    mockFactory = new JspFactory() {
      public PageContext getPageContext(Servlet servlet, ServletRequest servletRequest, ServletResponse servletResponse, String string, boolean b, int i, boolean b1) {
        return pageContext;
      }

      public void releasePageContext(PageContext pageContext) {
      }

      public JspEngineInfo getEngineInfo() {
        return null;
      }
    };

    JspFactory.setDefaultFactory(mockFactory);
    HttpJspBase manage = new com.objectmentor.library.jsp.WEB_002dINF.pages.books.manage_jsp();
    MockHttpServletRequest request = new MockHttpServletRequest();
    MockHttpServletResponse response = new MockHttpServletResponse();
    manage._jspService(request, response);
  }
}

Note all the mocks! Here is where the tomcat guys did a nice bit of work. The JspFactory is used within the generated servlet to gain access to all the objects it uses. It turns out that you can override the default implementation of the JspFactory by simply calling setDefaultFactory. Nice! That’s Dependency Management!

I did a quick breakpoint at the very end of my test and, sure enough, there is output stored in the MockJspWriter! Unfortunately, it’s nowhere near enough. The output stops as soon as the first tag was invoked. Indeed, there is a wonderfully silent return right in the generated code. No exception, no error message, just silent failure. sigh. Here’s the generated code:
      out.write("<form action=\"");
      if (_jspx_meth_library_actionPath_0(_jspx_page_context))
        return;
It was generated from this portion of the jsp.
<form action="<library:actionPath actionName="books/manage"/>" method="post" id="list_form">
The actionPath tag is one of our custom tags. All it does is much a controller path into an appropriate url format. (If you don’t understand that, don’t worry about it.) Clearly our custom tag is not being found. This is probably because the jasper compiler is not setting the _jspx_dependants variable properly. So now I need to figure out why…
For some reason, Jasper is not paying attention to the following line in my jsp file:
<%@ taglib uri="/WEB-INF/tld/LibraryTags.tld" prefix="library" %>
It’s not clear why, though I have to say that pattern of silent errors is really starting to bother me. An error message would certainly be nice.

Why is Jasper ignoring the taglib directive? The LibraryTags.tld file is there, and in the right place. The ActionPathTag.class file is in the classpath used to invoke jasper. I’ve played with the -uribase argument of the jasper compiler (for fun, read the description of this argument and see if YOU understand what it’s saying.) It’s a mystery…

Trackbacks

Use the following link to trackback from your own site:
http://blog.objectmentor.com/articles/trackback/128

Comments

Leave a response

  1. Avatar
    Brian Slesinsky about 16 hours later:

    Now you know why JSP’s are evil. There are large numbers of better template languages to choose from, so it’s no big loss.

  2. Avatar
    Dean Wampler about 1 hour later:

    Even James Duncan Davidson, the inventor of Ant, has publicly expressed his regrets that he chose XML as the format for ant files.

  3. Avatar
    Scott Carlson 1 day later:

    Hopefully Brian wasn’t refering to Tapestry as one of those templating languages. At least with JSPs there is some attempt at precompiles. In Tapestry, the magic between your HTML and your Java page are almost impossible to test outside of a full running application (though it can go in a Mock container).

    Incredibly painful and sloooow.

  4. Avatar
    Ravi Venkataraman 2 days later:

    One reason why you’d need to test JSP pages in a non-GUI environment is if the JSP had a lot of Java code in it. Tag libraries are one insidious way such code gets into JSPs.

    The way I look at JSPs is that they are a conduit to convey the information from the Web UI (Html) to the application server and vice versa.

    All I need to know is what action is requested and what data was present in the web page. The server uses this data to generate the data for the next page. A parser interprets this and generates the appropriate HTML page and passes this to the next JSP page, which presents it.

    I can test the parser separately, independent of the web server.

    Since the main work gets done in the Java code (Java Beans and classes), I can test the business logic independent of the web UI.

    That leaves me the simple task of validating that the UI is performing correctly, calling the correct Java Beans, etc. This is easy since I can easily modify the JSP pages on the fly with Tomcat running and see the changes.

    As a result of this architecture, we never need to test the JSP pages outside the web server.

    Come to think of it, why would one want to test the JSP page outside the web server? JSP pages must exist on the sweb server.

  5. Avatar
    Ravi Venkataraman 2 days later:

    David: “Why not automate it to make sure your changes to the business layer don’t have unexpected effects on your display?”

    Why should changes in business logic have any effects on my display? Isn’t that the whole idea of the Model-View-Controller paradigm – that the changes to the model (that are limited solely to the business rules) should not have an effect on the display? If the changes involve the UI, then we do have to test the UI anyway.

    In any MVC implementation with a clear separation between Mpdel and View, the issue should never arise. The fact that this question arises is an indication that the design might need to be tweaked.

    If the design is such that one must run the UI to test business rules that have no bearing on UI display, then, too, the design should be revisited.

    I simply do not see what additional benefit would be gained by testing JSP pages outside the container compared to testing the business rules alone.

  6. Avatar
    Uncle Bob 3 days later:

    JSPs are are programs that interpret an incomming data structure and produce HTML. To manually ensure that the mapping from that data structure to HTML is correct may require many different page views. For example, one might have session information that causes certain frames to be turned on or off, or there may be incoming flags that cause certain buttons to be greyed or activated.

    It seems prudent to me to test this code, including all it’s corner cases and boundary conditions. It also seems prudent to put these tests into a regression suite so that they don’t have to be re-run manually every time the session information, or the interface between the middleware and JSPs change.

    While I agree that it is wise to design your system to minimize the impact of such change, I also think it is wise to test that the impact has been minimized. Doing so econimically requires test automation.

  7. Avatar
    Ravi Venkataraman 4 days later:

    Uncle Bob said, “While I agree that it is wise to design your system to minimize the impact of such change, I also think it is wise to test that the impact has been minimized. Doing so econimically requires test automation.”

    Actually, I did not talk about minimizing the impact, I talked about eliminating the impact. And that can be designed.

    The example of frames, too, can be tested without using the UI. I will explain in another post.

    On another note, I see to it that my business classes never depend on the session parameter; they may have as parameters some bits of information available only through session object, but they never explicitly depend on it. Thus, you can still simulate the functionality without using the container.

  8. Avatar
    Uncle Bob 4 days later:

    I agree that the session object should not be used directly by the business objects. The session is the purview of the presentation portion of the controller code. The same is true of the view attributes. They should be set by the presentation side of the controller in order to direct the detailed behavior of the view.

    The prolem is that the view still has testable behavior that depends on those view attributes. So long as there is a single if statement or while loop in the JSP that is driven by those view attributes, automated testing of the view behavior is appropriate.

  9. Avatar
    Ravi Venkataraman 4 days later:

    Uncle Bob said, “So long as there is a single if statement or while loop in the JSP that is driven by those view attributes, automated testing of the view behavior is appropriate.”

    Agreed. But my argument is that even those attributes are data and should not have to be resolved by the JSP. In short, there should be no while blocks in the JSP. The only if blocks should be those that possibly determine what frame to display, what tab to switch to, etc. But even these can be accomplished without if blocks using JavaScript.

    As I said in my first post, I think of the JSP merely as a means to convey the web page data back to the application server. The application server then uses the data to generate some data and some sort of status. Using this information and a state machine concept, one determines the next action: what JSP page to display, what data and options to display, etc.

    In such scenarios, there is no need to test the JSP pages independent of the servlet container. There is a clean separation between the View and Model.

    In my design, there is a JspPage abstract class that serves as a controller. Each JSP page actually maps to one sub-class of this class. When some action is required, the particular sub-class acts as the controller, knows what Java Beans and classes have to be called, and what to do with the response from the JavaBeans class. Basically like what Struts and other tools do, but much simpler and more versatile.

    In these designs, we do not have to test the JSP page outside the servlet container.

  10. Avatar
    Uncle Bob 4 days later:

    How do you deal with variable length tables and lists if you don’t have loops in your JSPs?

    How do you deal with conditional messages (like errors) if you don’t have if statements in your JSPs?

  11. Avatar
    Ravi Venkataraman 4 days later:

    There are two substitutes for while loops:

    1. Have the Jsp ccontroller class spit out a string of HTML and have the JSP say something like: out.println(outputData);

    2. Have the data come in as XML and use XSLT to format the data, generating the desired JSP page. This XML/XSLT transformation can be performed programmatically at the back end if desired. Then the JSP reduces to the simple form as shown in #1 above. Of course, other approaches may involve using classes that can convert any Java Object directly to html format, using any desired display format (table, list. etc.) I like XSLT because, although verbose, it gives me some power in conditionally formatting the display. Also, the same data, or subsets thereof, can be displayed in completely different formats.

    As I’d mentioned earlier, in some cases “if” cases are unavoidable, such as tabs, choice of frames to display, message pop-ups, etc.

  12. Avatar
    Ravi Venkataraman 4 days later:

    I have often thought that Tomcat and other such tools are very heavyweight. All I want is for some mechanism to capture the data present in the HTML form on the page, and the required action, and pass it back to the server.

    Then, at the server end, we could do whatever is needed and send it back to the web layer. To do this, why do we need many of the features of Tomcat? If provided by the container, Database Connection pooling is useful. Session management through timeout, etc., is useful. But not much else.

    On a related note, why are the regular web browsers so poor at doing things such as (1) clicking on an html table column to sort by that column; (2) expanding text fields using drag and drop when the area is not sufficient; (3) easy implementation of simple contraints such as numeric only fields, date formats,, and so on. Such features would make it easy to develop web applications.

  13. Avatar
    Uncle Bob 5 days later:

    I’d rather not have my controller class know about HTML syntax. I think that belongs in something like a JSP. (Though Velocity would probably be a better choice.)

    I can’t say I’m a big fan of XSLT. That code can get pretty twisted, and it really needs to be tested.

  14. Avatar
    Ravi Venkataraman 5 days later:

    OK. You do what works for you.

    I’ll just keep it simple and cleanly separate my presentation layer from the business layer. I’ll also avoid the ugly and bloated code that results from mixing Java and HTML in a JSP. As a result of the clean separation of layers, I’ll end up writing less code and fewer tests but get a very robust and easily maintainable and extensible architecture.

  15. Avatar
    Ravi Venkataraman 5 days later:

    And by the way, in my architecture it is not the controller class that knows about the HTML syntax. In fact, none of my classes knows about it. I use some of the libraries provided by Java to transform XML to HTML. One could also write custom classes to convert objects to HTML, if one desired. And none of these would be in the controller class!

    Once the controller class gets the data (XML or Objects) from the server, it invokes the transformation classes and goes ahead presenting the result of the transormation to the view. The controller classes do not do the transform themselves.

  16. Avatar
    Ilja Preuss 9 days later:

    I only skimmed over the article, but you don’t need to manually precompile your JSPs to test them – ServletUnit can do that for you! http://httpunit.sourceforge.net/doc/faq.html#JSP

    It’s a well hidden feature, but it works great, in my limited experience…

  17. Avatar
    FLV to ipad converter over 3 years later:

    jus t so what

  18. Avatar
    Area Rugs Best Buys over 4 years later:

    This is a good blog. Keep up all the work. I too love to blog. This is great everyone sharing opinions.

  19. Avatar
    Pandora over 4 years later:

    on’t belittle or humiliate people who didn’t have the chance to learn how to write good code.

  20. Avatar
    iPad video converter for Mac over 4 years later:

    When I come to here, I think I am in the right place. the web gives me a lot of infomation, it is very informative. I think lots of people can learn much here. I will come to here again. Thanks.

  21. Avatar
    Silicone Molding over 4 years later:

    Mold making is the core business of Intertech (Taiwan). With world level technology, Intertech enjoys a very good reputation for making Injection Mold and Plastic Moldsfor their worldwide customers.

  22. Avatar
    Criminal Check over 4 years later:

    The JspC ant task wants to compile the WHOLE web app for me. And this is such a good information. Keep posting useful and informative articles.

  23. Avatar
    Criminal Records over 4 years later:

    All I want is for some mechanism to capture the data present in the HTML form on the page, and the required action, and pass it back to the server.

  24. Avatar
    Tenant Screening over 4 years later:

    One could also write custom classes to convert objects to HTML, if one desired. And none of these would be in the controller class!

  25. Avatar
    ipad bag over 4 years later:

    Top best Combine Follow ipad bag the detail tips below, you can increase the laptop battery life of a year or more. Game Controllers first thing you should care about the USB Gadgets END!

  26. Avatar
    King papa over 4 years later:

    Another informative post. I like it this is great. Thanks. roof nokomis

  27. Avatar
    seo over 4 years later:

    Keep posting useful and informative articles.it is very informative. I think lots of people can learn much here. I will come to here again. Thanks.

  28. Avatar
    okey oyunu oyna over 4 years later:

    nice post i will use it…Thanks

    Dünyan?n en büyük online okey oyunu bu sitede sizleri bekliyor. Gerçek ki?ilerle sohbet ederek Okey Oyunu Oyna ve internette online oyun oynaman?n zevkini ç?kar

  29. Avatar
    cheap brand watches over 4 years later:

    It is really a nice post, it is always great reading such posts, this post is good in regards of both knowledge as well as information. Very fascinating read, thanks for sharing this post here.

  30. Avatar
    real estate advertising over 4 years later:

    a very informative post… full of information. i love it.. thanks for sharing.

  31. Avatar
    beats by dr dre headphones over 4 years later:

    Some beats by dr dre solo purple training routines that will improve Your Voice instantly when you exercise Them!These training routines are extremely effective at erasing bad habits, and replacing them using a “successful”, fabulous sounding voice. The headphone’s exterior is produced from an ultra glossy complete that’s particular to garner some attention in beats by dr dre pro black.

  32. Avatar
    Cookies Gift over 4 years later:

    hmm ,i’m not sure if this is what i’m looking for but anyway this is interresting and could be useful some day,thanks for taking time to write such cool stuff

  33. Avatar
    adres zoeken op naam over 4 years later:

    a very informative post… full of information. i love it.. thanks for sharing. love it!

  34. Avatar
    beats by dre store over 5 years later:

    , fabulous sounding voice. The headphone’s exterior is produced fromcheap beats by dre beats by dre store

  35. Avatar
    shanewatson404@gmail.com over 5 years later:

    Wow, this is Legal Assistant Job Description really superb info is visible in this blog Director of Operations Job Description that to amazing Accounting Job Description technology and using the wonderful messages for this website. I was searching the great info and providing the nice info in this blog and read Graphic Designer Job Description this info you can never forget this info

  36. Avatar
    hub over 5 years later:

    This How To Become A California Resident is really How To Become A GAME WARDEN great info is visible How To Become A Real Estate Appraiser in this blog How To Become A Politician and sharing How To Become A Fireman the nice How To Become A Corporation technology in this blog How To Become A Wedding Consultant

  37. Avatar
    hub over 5 years later:

    I am very much How To Become A Travel Writer enjoyed for the great How To Become An Animal Cop services How To Become Cameraman in this blog and How To Become A Dominatrix using the nice technology in this blog How To Become A Hair Model This is very much happy how To Become A Travel Agent From Home for using the nice services in this website

  38. Avatar
    hub over 5 years later:

    This is really nice technology in this blog and utilizes How To Become A Fashion Photographer the amazing How To Become Neurologist technology in this blog. Thanks a lot for providing the nice info is visible in this blog

  39. Avatar
    Tips For Bowling over 5 years later:

    FOR a long time the conviction has been dimly felt in the community that, without prejudice to existing institutions, the legal day of weekly rest might be employed to advantage for purposes affecting the general good.

  40. Avatar
    nike women heels over 5 years later:

    As for Women and jordan high heels, this is the inseparable relations, Tom Ford master evidence: “don’t wear the high-heeled shoes woman how talk up sexy?” High heels and sex appeal is relevant? The answer is: “of course!”

  41. Avatar
    christian louboutin over 5 years later:

    Peep toe shoes used to be popular, now it regress popular again. Too heavy and dramatic square toe shoes may be nightmare for many people, but open a mouth in front, the effect will be greatly different. For women, it is a very good transition. It is very trendy, but unlike pointed toe shoe so eye-catching. In this year, a pair of delicate Christian Louboutin Peep Toe Pumps will be a good choice.

    Christian Louboutin Madame Butterfly 150 Suede Pumps Red

    Technical details of Christian Louboutin Madame Butterfly 150 Suede Pump Red:

    Color: Red
    Material: Suede
    Peep toe
    6(150mm) covered heel
    1.5(35mm) covered platform

    Fashion, delicate, luxurious Christian louboutins shoes on sale, one of its series is Christian Louboutin Peep Toe Pumps, is urbanism collocation. This Christian louboutins shoes design makes people new and refreshing. Red soles shoes is personality, your charm will be wonderful performance.

  42. Avatar
    alwadifa 2012 over 5 years later:

    Keep posting useful and informative articles about java

  43. Avatar
    cheap cigarettes shop over 5 years later:

    cigarettes online history of aircraft manufacturing is full of so many exciting designs and displays. A flying machine concept has cheap cigarettes shop the maximum significance and has turned to a vital manufacturing industry since decades.

  44. Avatar
    coach handbags uk over 5 years later:

    Its like you read my mind! You appear to know so much about this, like you wrote the book in it or something.

  45. Avatar
    brother ink over 5 years later:

    Genuine and original Brother inkjet cartridges in UK. Brother ink cartridges for the best quality printing from Brother printers.

  46. Avatar
    louboutin sales over 5 years later:

    Ant, JspC, and Other Horrors. 45 hoo,good article!!I like the post!7

Comments