A collection of tips for Java development.
Common exceptions
-
java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;
This exception results from attempting to use Java EE 5 components (such as JSF 1.2) in a J2EE 1.4 environment. Either the container does not support Java EE 5 or you have the 2.4 servlet API somewhere in the runtime path.
Ajax4Jsf
-
a4j:support —
this.control
provides a handle to the parent DOM object (the object in which the a4j:support tag is nested.
Facelets
-
Content-Type - the default Content-Type in Facelets >= 1.1.12 changed to application/xhtml+xml from text/html. This is known to break several JavaScript libraries, including the Google Maps API. To switch back to text/html, place the following tag inside your ui:composition:
<f:view contentType="text/html">
<!-- remaining template markup -->
</f:view>
-
ui:composition
-
ui:define and ui:param must be direct descendants of ui:composition
-
c:set must occur inside of ui:define to be passed to template
-
f:loadBundle must be placed inside the ui:composition tag to be available to template blocks inserted with ui:insert
-
-
custom tomahawk attributes (ie forceId) → described in detail on the MyFaces Wiki
-
use fully qualified name of the attribute
-
implement TagHandler and override createMetaRuleset to add an alias
-
use f:attribute to assign in facelets to avoid creating and registering a TagHandler class
-
Resolving templates in the classpath
To provide reusable Facelets templates, you may want to put them in a jar file, rather than exploded in the root of the webapp. There are two ways to resolve templates in a jar file.
-
custom ResourceResolver - the universal way is to implement a custom ResourceResolver that will look into the classpath for Facelets templates. This class is then registered under the
facelets.RESOURCE_RESOLVER
servlet context parameter. `import com.sun.facelets.impl.DefaultResourceResolver; import com.sun.facelets.impl.ResourceResolver; import java.net.URL; public class ClasspathResourceResolver extends DefaultResourceResolver implements ResourceResolver {public URL resolveUrl(String path) { URL url = super.resolveUrl(path); if (url == null) {
if (path.startsWith("/")) { path = path.substring(1); }
url = Thread.currentThread().getContextClassLoader().getResource(path); } return url; } }` . *relative to tag library* - the other way is specific to the development of a tag library. Package the *.taglib.xml file in the /META-INF folder of the jar file. Then, the template files are search relatively to the taglib file location, hence within the same jar file.
JPA
Java EE 5 has a nice feature that any META-INF/persistence.xml will be picked up automatically and you can use @PersistenceUnit, @PersistenceContext, and @Resource in servlets (not that you would ever want to write a servlet). However, for this feature to work, your web.xml must be using the 2.5 XSD schema. Below is the declaration you will need:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- ... -->
</web-app>
JSF
-
Keep in mind that if validation fails, model values will not be updated.
-
The JSF EL (hopefully fixed in the unified EL) does not properly handled escaped characters (prefixed with the backslash character). For instance, the EL expression
#{'That's all folks'}
will result in an error. One workaround is to use the angled single quote entity ’ to emulate the single quote character. -
The client and server state saving methods, as defined by the servlet initialization parameter javax.faces.STATE_SAVING_METHOD, have very different semantics. When objects are stored in the component tree, they are not serialized when the state is stored on the server. However, if client state saving is active, they will be serialized because they must be exported to a string value. If serialization does not occur, transient properties are not cleared and object identities are maintained. Unfortunately, without careful testing, it is not trivial to switch between the two methods. Additionally, JSF DataModel objects cannot be serialized, a potential cause of headaches when using client-side state saving.
Hibernate
Spring
-
Use the & character in the spring XML configuration to inject the actual FactoryBean and not its product. This technique may be especially useful in unit testing.
-
Getting started with JPA (also has testing advice)
Error Pages
IE overrides several HTTP error status pages, but it does have a size threshold. Basically, if the error page sent by the server has a large enough body then IE decides it’s meaningful and displays it. Usually, to be safe, you should make error pages that are larger then 512 bytes. The threshold varies per HTTP status code and can be modified via the Windows Registry.
Domain Model
In general, it is a good idea to delegate the instantiation of domain objects to an object factory. While ORM tools would use the constructors directly, the business logic would request a complete object from the factory.
Order order = new OrderFactory().createOrder( "1", "order1" );
Hibernate Logging (on JBoss AS)
You don’t need any logging libraries in your WAR file. All of the logging is handled at the application server level. That’s just how it is with JBoss AS. There are ways around it. See the JBoss at Work book for more info.
The jboss-log4j.xml file that you need to edit resides in $JBOSS_HOME/server/default/conf for the default domain
You can either set the Hibernate logging in the Log4j configuration or in the Hibernate property, but not both. Here are the rules:
-
If you set the org.hibernate.SQL category in jboss-log4j.xml to DEBUG, Hibernate will log the SQL statements. By setting the org.hibernate.SQL category, the Hibernate property hibernate.show_sql has no effect.
-
If you don’t set the org.hibernate.SQL category at all in the jboss-log4j.xml, Hibernate will use the hibernate.show_sql property to determine whether or not to log the SQL statements.
You can also format the SQL by setting the Hibernate property hibernate.format_sql to true. This property works regardless of how you enable SQL logging.