When JBoss Seam Fails

seamYesterday I wrote about Ruby on Rails and what happens when programmers make common (typing) mistakes in their programs. It seems to have hit a nerve.

A number of Java and C# programmers sat back and enjoyed the show. "See what happens when you don’t have static typing in your language? In your face, smug Ruby on Rails sons of guns!"

Indeed, statically typed language fans often argue that many such common mistakes, such as misspelled variable, method, type and field names are found much faster: at compile time — hell, with Eclipse almost as you type! And this is definitely true. However, errors are only found within Java code. Modern web applications are built using a number of domain-specific languages that interact with Java in various ways – JSF, regular expressions, SQL or HQL and various sorts of XML configuration files. Once Java start interacting with other languages, things start going wrong and static typing is no longer helpful.

In this article I demonstrate this problem by showing examples of code built using JBoss Seam, a modern Java framework for developing web applications. Seam is essentially glue to put a number of popular Java frameworks together in a developer-friendly manner. It relies on frameworks and technologies such as Hibernate, JSF and EJBs. Interaction between the languages are very error prone, it turns out. Other Java frameworks, such as the Spring framework have similar issues. People say the Play Framework does a better job. So play framework people, if you’re listening (and I know you are), if you’re still so confident about yourself after reading this article, let me know, I’ll have a good look at Play. But for now, let’s focus on JBoss Seam.

Like with Ruby on Rails, I will consider a number of easy to make mistakes, and see how the framework responds to it. These mistakes are exemplary of problems that Java frameworks like Seam have, even though they are based on a statically typed language. They cannot be used as a fair comparison to e.g. Ruby on Rails.

Mistake #1: Use non-existent property of a variable in a JSF page

Welcome #{user.nam}

The user object does not have a nam property, only a name property. As we compile our code, the compiler reports no errors. However, when we deploy and load the page we see:

seam-fail-1

Although the error is clear, it is left for us to figure out where this nam property is actually used. Apparently there is no compile-time checking of JSF pages against the backing Java beans they communicate with.

Mistake #2: Non-existent references to pages

Seam has a pages.xml file to control flow between pages under certain conditions. The page contains references to Java code (in #{…} expressions) and to views (.xhtml pages). However, neither of these are checked at compile time, so if we mistype a page name:

<page view-id="/home.xhtml" action=
"#{identity.isLoggedIn}">
    <navigation>
        <rule if="#{identity.loggedIn}">
            <redirect view-id="/man.xhtml"/>
        </rule>
    </navigation>
</page>

We are get a 404 Not found error.

seam-fail-2

Mistake #3: Faulty validation regular expression

Validation of data model properties based on regular expression can be defined using the @Pattern annotation. But what happens when the programmer puts in a syntactically invalid regular expression?

@Pattern(regex="^[\\w*$", message="not a valid username")
public String getUsername() {
   return username;
}

There is a ‘[‘ too many there. When the code is compiled, no error is found. However, when it is deployed to the application server, an exception with an enormous stack trace appears:

seam-fail-3

It’s clear there is a regex mistake here. Somewhere. But where exactly is very hard to pinpoint drowning in the trace.

Mistake #4: Making a mistake in a HQL query

The Java Hibernate framework uses its own variant of SQL, that is slightly higher-level than SQL. Queries are represented as strings, and only checked at runtime.

List existing = em.createQuery("select u.username from User like u where u.username=#{user.username}")
     .getResultList();

There is a mistake here because there should not have been a "like" there in that query. When the action is invoked, an exception is thrown with an even longer stack trace than before:

seam-fail-4

A similar exception occurs 7 times in the stack trace, only on a few location there is actually a reference to the location in the code where the problem occurred:

at org.jboss.seam.example.booking.RegisterAction.register(RegisterAction.java:40)

Bad.

Conclusion

Compared to Ruby on Rails, the ability to type check Java code is a nice feature and lets you find a certain kind of mistake very quickly — in an IDE such as Eclipse even as you type. This support rapidly degrades when moving outside the statically typed world of Java. As soon as the programmer has to jump to using strings, as is the case when using e.g. regular expression, SQL and HQL, the safe, checked world of Java comes to an end.

The only kind of checks that are performed in languages like Java are type checks. This also means that the only mistakes are found that are related to types and can be expressed in types. This gets you only up to a certain point in finding programming errors. In order to use regular expressions in Java, programmers have to encode them in strings; SQL queries are encoded in strings — compilers do not check strings. Strings are parsed and interpreted only at runtime, meaning problems only appear at runtime typically buried in an enormous stack trace. And that’s a big shame.

Next part in this series: When Scala DSLs Fail.

Tags: ,

  • Modern web applications are built using a number of domain-specific languages that interact with Java in various ways – JSF, regular expressions, SQL or HQL and various sorts of XML configuration files. Once Java start interacting with other languages, things start going wrong and static typing is no longer helpful.
  • Nicolas
    As we see, all of these problem can or could be adressed.

    It is possible to make/include validator in the build prcess and simply make the build fail if there is an error.

    JSP and alike should not permit "script like" syntax, but only clean and statically typed code. It could be even included in the design.

    I prefer to use a full object framework like GWT or Zk that permit to have static checks for many more part of my code that frameworks based on templates and script. In the long run it save a lot of time.

    Oh and it not only static compiled programs give to you, but a much more common mistake : you misspelled your identifier. (And this in dynamic languages or scripts like JSP, it doesn't work).

    Another good thing with IDE this time, is that they can give you all methods, valids identifiers and all with their type anywere you need it and instantly. IDE doesn't just detect error, they help you write a correct code in the first place.
  • philip andrew
    If you use IntelliJ Idea it picks up all these errors in the IDE and highlights them in RED.
    I'm not advertising their product, just state a fact.
  • Ashitkin Alexander
    for me it's a regular article for the subject 'man with axis can break it all'. IDEA has amazing seam support, so if you miss something - visit your oculist as the first step to an error free application.
  • kk
    Mistake #4: JPA _named_ queries are validated when deploying, not at runtime.
  • How about a an article with the title: When JSR standards fail?
    http://luxspes.blogspot.com/2009/11/jpa-myth-ec...
  • sannegrinovero
    Hi, nice post.
    You forgot a point: the names of injected components. An important issue, especially as the solution in Weld/Seam3 is so cool.
    Also consider that using JBoss Tools you're pretty much covered: you can even refactor method names it will find and update the references in facelets. As mentioned above, IDEA also helps; noone is using Vim or notepad with Seam I guess.
    About the Pattern problem, could it be considered a Java language limitation?
    Everybody writing a regex should have some unit tests convering them, so you're sure they will at the very least compile.
  • Couldn't agree more :-)

    Better error reporting is something we are working hard on for Weld/Seam 3.
  • @zef, your tests are very interesting. As a lot of people say, playframework try to be very good at this particular point. But there is no magic. We have to manage each problem specifically, trying to find the most interesting underlying exception for each particular error.

    I would love to see a 'When Play framework Fails' post. I hope better results. But as I said there is still no magic in play. You will surely find badly reported errors in you try hard enough.

    However I think that the difference with most projects is that we consider badly reported errors as a real bug.
  • Matt Drees
    "we consider badly reported errors as a real bug"

    I love that mentality. I wish more projects had it.
  • Jan Groth
    @Stephen - just to mention the obvious: if you rely on IDE-highlighting, and overlook just a little yellow dotted line or so (-> BTW, I'm colorblind... ) the next level of quality assurance can be your customer calling...
  • Stephen Friedrich
    I agree with all your points. For me the conclusion however is to use a smart IDE.
    IntelliJ IDEA prevents all these mistakes by giving live warnings while coding:
    #1: EL expressions are validated against the java beans.
    #2: Page references in pages.xml are validated.
    #3: Regular expression syntax is also checked while typing
    #4: HQL queries in strings are fully supported including validation and code completion (in latest builds even with nested EL expressions like #{user.username})

    IMHO there still is a fundamental difference in between these kind of languages (EL, HQL, RegExp) and dynamically types languages like Ruby.
    For the first kind of languages it is at least theoretically possible to do strict static type checks. It is more an issue with language tools.
    In Ruby all static checks have to be best guesses (correct me if I'm wrong).
  • As Emmanuel mentioned, some of these kinds of errors are actually detectable using our eclipse toolset, and we are definitely getting even better with JPA2 and CDI. (Typesafety was a major goal.)

    But I agree with your broader point that things start to go bad once you leave Java.
  • Interesting feedback,
    JPA 2 will bring a solution to Mistake #4 via the Criteria API
    and I think I have a solution for Mistake #3 for Hibernate Validator 4 ( http://opensource.atlassian.com/projects/hibern... ): a compile time we will detect these type of errors

    We are making progress. The idea is to represent more in Java and less in String, a move we have started a few years ago. It takes time though.
  • MAG
    As far as I remember JBoss Tools for Eclipse does highlight error #1.
  • rbohn
    So are you proposing an alternative that fixes all of these issues or are you just pointing out the obvious?
  • This is all just a long analysis section of an upcoming paper we're writing. And yes, there will be a solution in the end ;)
  • Syntax errors in SQL and regexps could be detected early if they were part of the host language's syntax instead of being buried in strings.

    For example:
    MetaBorg in Action: Examples of Domain-specific Language Embedding and Assimilation using Stratego/XT: http://martin.bravenboer.name/docs/metaborg-gtt...

    But also take a look at something as .NET's LINQ syntax. A domain specific language for querying anything monadic.
  • Thiago
    Where's Mistake #3?
  • Good point. Mixed up the numbering there. Fixed. Thanks.
blog comments powered by Disqus