Type of expression language (JSTL-EL) loop and collection variables

Hi. I'm currently evaluating IntelliJ IDEA 7 and hope to persuade management to upgrade from 4.5, since there are a couple of nifty features that may make it worthwile. On of them is the expression language awareness (code completion, refactoring etc) in JSP pages.

We have an MVC model where the beans are put in request scope by a servlet. In this case I can add a <jsp:useBean /> tag to the page, just for IntelliJ.
But, in many cases the servlet also adds Maps and Lists to the request, and then we use EL to loop the List or look up values in the Map. It seems I am able to put a <jsp:useBean /> inside the loop, to have IntelliJ detect the type.

My questions:
- Is it possible to make IntelliJ aware of the types of loop variable by some other means? It understands the var attribute on our custom loop tags, but adding a class attribute didn't seem to work.
- It is possible to make IntelliJ aware of the collections in the request, to avoid the "Cannot resolve variable XYZ" warning without turning the inspection off? <jsp:useBean /> can only be used for beans.
- Is there any other way to make the page aware of request scope variables? Sometimes we don't want the <jsp:useBean /> to create a new bean if there is none, but rather be able to separate between a bean instance being provided by the servlet and not (i.e. null).

Thanks in advance.

6 comments

Hello Mattias,

Hi. I'm currently evaluating IntelliJ IDEA 7 and hope to persuade
management to upgrade from 4.5, since there are a couple of nifty
features that may make it worthwile. On of them is the expression
language awareness (code completion, refactoring etc) in JSP pages.

We have an MVC model where the beans are put in request scope by a
servlet. In this case I can add a <jsp:useBean /> tag to the page,
just for IntelliJ.

But, in many cases the servlet also adds Maps and Lists to the
request, and then we use EL to loop the List or look up values in the
Map. It seems I am able to put a <jsp:useBean /> inside the loop, to
have IntelliJ detect the type.


One thing that works for me is <jsp:useBean/> specifying an array type.
IDEA will understand that the current loop value of <c:forEach> will be of
the component type of the array.

Another possibility is to use a generic List or Map declaration in <jsp:useBean/>.
(I works on the containers I've used, but check yours first).

My questions:

- Is it possible to make IntelliJ aware of the types of loop variable
by some other means? I tried adding a class attribute to our custom
tags, but it didn't seem to work.


I think custom tags are a different issue than request attributes registered
by a servlet.
Can you show the TLD, and describe what problem you see?


- It is possible to make IntelliJ aware of the collections in the
request, to avoid the "Cannot resolve variable XYZ" warning without
turning the inspection off? <jsp:useBean /> can only be used for
beans.


<jsp:useBean id="myList" type="foo.bar.Baz[]" scope="request"/>
or
<jsp:useBean id="myList" type="java.util.List<foo.bar.Baz>" scope="request"/>

IDEA will correctly undestand the type of the "current loop iteration variable"
for above examples (when using <c:forEach>).


- Is there any other way to make the page aware of request scope
variables? Sometimes we don't want the <jsp:useBean /> to create a new
bean if there is none, but rather be able to separate between a bean
instance being provided by the servlet and not (i.e. null).


Use a <jsp:useBean/> declaration inside an <c:if test="!empty(requestscope.foo)">
block?

The important detail here is that <jsp:useBean/> has two "modes of operation":
1) When using the "class" attribute, you're using the "stone-age" JSP <jsp:useBean/>
feature:
-"class" must refer to an instantiable type (bean)
-when not found in scope, a new instance will be created
-this is a really old (pre-JSP 1.0?) usage model
-you don't need/want this!

2) When using the "type" attribute:
-Nothing will ever be instantiated/created by <jsp:useBean/>
-However, a check is done that the attribute value is present
-"type" is not restricted to instantiable types: you can use interfaces to
reduce coupling (when it makes sense)

In short, <jsp:useBean type="..."/> works like an assertion that checks the
presence of required model data. It also adds documentation (and the ability
to refactor) to your JSP views.
My answers above are assume you're using the "type" mode, by the way.

Perhaps you have "J2EE Design and Developement" (old book by Rod Johnson)
lying around? It talks about using <jsp:useBean type="..."/> to cleanly "declare"
the "data requirements" of a JSP view (ch 13, p. 531).

Hope that helps,

Taras


0

The important detail here is that <jsp:useBean/> has
two "modes of operation":
1) When using the "class" attribute, you're using the
"stone-age" JSP <jsp:useBean/>
feature:
...
-this is a really old (pre-JSP 1.0?) usage model
-you don't need/want this!

2) When using the "type" attribute:
...
-"type" is not restricted to instantiable types: you
can use interfaces to
reduce coupling (when it makes sense)


Since I haven't actually used the <jsp:useBean /> I was still living in the stone age... I had no clue about the type attribute. It solved most of my problems!

One thing that works for me is <jsp:useBean/>
specifying an array type.
IDEA will understand that the current loop value of
<c:forEach> will be of
the component type of the array.

Another possibility is to use a generic List or Map
declaration in <jsp:useBean/>.
(I works on the containers I've used, but check yours
first).


Resin does not support generics, but I've filed a feature request.

<jsp:useBean id="myList" type="foo.bar.Baz[]"
scope="request"/>
or
<jsp:useBean id="myList"
type="java.util.List<foo.bar.Baz>" scope="request"/>

IDEA will correctly undestand the type of the
"current loop iteration variable"
for above examples (when using <c:forEach>).


Yes, using an array type works fine. Is there any workaround for Maps until Resin supports generics?

I think custom tags are a different issue than request attributes registered
by a servlet. Can you show the TLD, and describe what problem you
see?


Actually, the type attribute works just fine with my custom tags too!

Use a <jsp:useBean/> declaration inside an <c:if
test="!empty(requestscope.foo)">
block?


My solution:
<c:if test="false">
<jsp:useBean id="..." type="..." />
</c:if>

0

Hello Mattias,

>> One thing that works for me is <jsp:useBean/>
>> specifying an array type.
>> IDEA will understand that the current loop value of
>> <c:forEach> will be of
>> the component type of the array.
>> Another possibility is to use a generic List or Map
>> declaration in <jsp:useBean/>.
>> (I works on the containers I've used, but check yours
>> first).

Resin does not support generics, but I've filed a feature request.


The part of the JSP specification describing <jsp:useBean> long predates
Java5/generics, and has't received any updates in recent years.
It doesn't contain anything that explicitly forbids such usage though.

I've written the JSP expert group in the past with a request to update the
section, since there clearly is a practical usecase.
However, I've never received any response. I'm not sure what's the proper
way to request such spec clarifications..

>> <jsp:useBean id="myList" type="foo.bar.Baz[]"
>> scope="request"/>
>> or
>> <jsp:useBean id="myList"
>> type="java.util.List<foo.bar.Baz>" scope="request"/>
>> IDEA will correctly undestand the type of the
>> "current loop iteration variable"
>> for above examples (when using <c:forEach>).

Yes, using an array type works fine. Is there any workaround for Maps
until Resin supports generics?


Could you quote a small example of your current JSP/JSPX code?

>> I think custom tags are a different issue than request attributes
>> registered
>> by a servlet. Can you show the TLD, and describe what problem you
>> see?

Actually, the type attribute works just fine with my custom tags too!


In most cases you should not even need to use it, IDEA should be able to
detect the type coming from custom tags automatically.
Can you provide some example code (TLD and Java tag source)?

Regards,

Taras


0

Could you quote a small example of your current
JSP/JSPX code?


Example:
Servlet:
Map<String, foo.Bar> bars = ...;
request.setAttribute("bars", bars);

JSP:
<jsp:useBean id="bars" type="java.util.Map" scope="request" />
...
<c:out value="${bars[barId].nonDetectedMember}" />

In most cases you should not even need to use it,
IDEA should be able to
detect the type coming from custom tags
automatically.
Can you provide some example code (TLD and Java tag
source)?


Yes, I meant that IDEA did auto detect this from my items and var attributes, if there was a useBeans tag for the items.

0

Hello Mattias,

>> Could you quote a small example of your current
>> JSP/JSPX code?

Example:
Servlet:
Map<String, foo.Bar> bars = ...;
request.setAttribute("bars", bars);
JSP:
<jsp:useBean id="bars" type="java.util.Map" scope="request" />
...
<c:out value="${bars[barId].nonDetectedMember}" />


You can use something like this instead of <jsp:useBean>:
<!@elvariable id="foo" type="java.util.Map<java.lang.String,java.lang.Integer>">

It's an IDEA-specific annotation comment.
Note that for unresolved EL variables you can invoke Alt-Enter to automatically
insert either <jsp:useBean> or the above annotation comment.

>> In most cases you should not even need to use it,
>> IDEA should be able to
>> detect the type coming from custom tags
>> automatically.
>> Can you provide some example code (TLD and Java tag
>> source)?

Yes, I meant that IDEA did auto detect this from my items and var
attributes, if there was a useBeans tag for the items.


Can you give some more details (with sample code)?
Note that IDEA recognizes tag-defined variabled by looking at ]]>
element in TLD, as well as analyzing optional TEI classes, if present.

Or perhaps you're talking about JSP 2.0 tag files?

Taras


0

You can use something like this instead of
<jsp:useBean>:
<!--@elvariable id="foo"
type="java.util.Map<java.lang.String,java.lang.Integer
>"-->

It's an IDEA-specific annotation comment.


Now that's what I'm looking for.

Can you give some more details (with sample code)?


What for? My problem is solved.

0

Please sign in to leave a comment.