javax.servlet.jsp cannot be resolved to a type

jsp-ide-error

If your IDE produces an error like javax.servlet.jsp cannot be resolved to a type you shuold include the jsp-api dependency to solve that:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>

Make sure that the scope is provided, because the servlet container that we use to run our project will provide this dependency. This is because the jsp-api is not required when compiling your project, it is only needed when you run the project (aka it is a runtime dependency).

For me, this error came up in STS (which is a variation of Eclipse), but you can expect it in other IDEs as well.

How to get the current context path in a JSP file

Most of the times when you want to place a link somewhere in you web application you want it to be relative to the context path (the root path under which your application is available).  This way, no matter where you navigate in your application, the link will always point to the same page.

In a JSP page you can use the following EL expression to get the context path:

${pageContext.request.contextPath}

For exmaple, if my context path is /jtuts and I want to set the action of a form to point to /jtuts/register then I would be able to do it the following way:

<form:form commandName="userForm" action="${pageContext.request.contextPath}/register" method="post">
    <!-- Contents skipped for brevity. -->
</form:form>

Apostrophes stripped, parameters not evaluated when using the spring:message tag

The <spring:message> tag is often used in JPSs to output localized messages that are read from property files. In most cases it outputs the expected message without problem, but if you have apostrophe(s) in a message, there could be some unexpected results. The following could happen:

  • The apostrophes in the message are stipped, not visible.
  • Some of the parameters in the messages don’t get replaced by the arguments passed in. As a result the paramter placeholder is displayed.

Let’s see some examples that demonstrate this problem. First, we create a ReloadableResourceBundleMessageSource object that will let us access the messages in our property files. This object is created like this in the application context xml:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="basenames">
        <list>
            <value>classpath:i18n/messages</value>
        </list>
    </property>
</bean>

We also create a property file that will contain the messages and we output them using the <spring:message> tag in our JSP files.  Our property file is placed here to match the configuration of the messageSource bean:

/src/main/resources/i18n/messages.properties

Now let’s see some example properties and the result of them. Our properties are:

home.paragraph1=There is no apostrophe in this message.
home.paragraph2=There is no apostrophe in this message, but it has {0} and {1} parameters.
home.paragraph3=Look it's an apostrophe, but no params.
home.paragraph4=Look it's an apostrophe, and it has {0} and {1} params.
home.paragraph5=Look it's it's two apostrophes, and it has {0} and {1} params.
home.paragraph6=Look it's two apostrophes, {0} but they're between the parameters {1}.

In the JSP we diplay them like this:

<p><spring:message code="home.paragraph1"/></p>
<p><spring:message code="home.paragraph2" arguments="P1,P2"/></p>
<p><spring:message code="home.paragraph3"/></p>
<p><spring:message code="home.paragraph4" arguments="P1,P2"/></p>
<p><spring:message code="home.paragraph5" arguments="P1,P2"/></p>
<p><spring:message code="home.paragraph6" arguments="P1,P2"/></p>

And the result is:

There is no apostrophe in this message.
There is no apostrophe in this message, but it has P1 and P2 parameters.
Look it's an apostrophe, but no params.
Look its an apostrophe, and it has {0} and {1} params.
Look its its two apostrophes, and it has P1 and P2 params.
Look its two apostrophes, {0} but theyre between the parameters P2.

As you can see, when apostrophes and parameters are both present, the apostrophes always disappear, but only some of the parameters are not evaluated.

The logic behind the magic

Before a message is printed, the ReloadableResourceBundleMessageSource object that we use passes messages through a call to the MessageFormat.format() method. This substitutes the arguments and formats them property. During this call the apostrophe has a special meaning, it encloses parts of the string that should not be evaluated. Also, after parsing the string all single apostrophes are removed.

If you look at the previous examples you can see that where parameters are present the apostrophes really disapear, and if a parameter is after an “opening” apostrophe it is not evaluated.

However, note that the third example has apostrophe in it but it is not removed from the string when it is printed. This is because for optimization reasons only messages that contain parameters are passed through the formatter method. The rest of the messages are just printed as is.

Using apostrophes and parameters together, the right way

If you would like for an apostrophe to display in a string where there are also parameters, you must write double apostrophes. They will be converted to single ones, and parameters will not be harmed.

So let’s take our fourth example and modify it to get the expected result. We just have to add an extra apostrophe:

home.paragraph7=Look it''s an apostrophe, and it has {0} and {1} params.
Look it's an apostrophe, and it has P1 and P2 params.

So sometimes you have to add double apostrophes, and sometimes not. Won’t this cause a confusion?

Yes, probably it will. But there is a way to force the ReloadableResourceBundleMessageSource object to work the same way every time. You can set a parameter on it that will cause all messages to go through the MessageFormat.format() method. So this way you can be sure that you can use double apostrophes every time you need to print an apostrophe. To enable this option, modify the bean definition like this:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="alwaysUseMessageFormat" value="true"/>
    <property name="basenames">
        <list>
            <value>classpath:i18n/messages</value>
        </list>
    </property>
</bean>

Download source

You can download the source files used in this project here.