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.
Please sign in to leave a comment.
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).
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?
<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>).
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
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!
Resin does not support generics, but I've filed a feature request.
Yes, using an array type works fine. Is there any workaround for Maps until Resin supports generics?
Actually, the type attribute works just fine with my custom tags too!
My solution:
<c:if test="false">
<jsp:useBean id="..." type="..." />
</c:if>
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).
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>).
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?
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
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}" />
Yes, I meant that IDEA did auto detect this from my items and var attributes, if there was a useBeans tag for the items.
Hello Mattias,
>> Could you quote a small example of your current
>> JSP/JSPX code?
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)?
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
Now that's what I'm looking for.
What for? My problem is solved.