tags:

views:

549

answers:

3

Let's say I have simple Login servlet that checks the passed name and creates User object and stores it in a session.

User user = new User();
user.setId(name);

request.getSession().setAttribute("user", user);
response.sendRedirect("index.jsp");

In the index.jsp page I access the user object through jsp:useBean

<jsp:useBean id="user" scope="session"
             class="package.name.User"/>

<div class="panel">
    Welcome ${user.id}
</div>

It works so far.

From the jsp beans documentation

To locate or instantiate the Bean, takes the following steps, in this order:

  1. Attempts to locate a Bean with the scope and name you specify.
  2. Defines an object reference variable with the name you specify.
  3. If it finds the Bean, stores a reference to it in the variable. If you specified type, gives the Bean that type.
  4. If it does not find the Bean, instantiates it from the class you specify, storing a reference to it in the new variable. If the class name represents a serialized template, the Bean is instantiated by java.beans.Beans.instantiate.
  5. If has instantiated (rather than located) the Bean, and if it has body tags or elements (between and ), executes the body tags.

The questions:

Attempts to locate a Bean with the scope and name you specify

It does not specify the "locate" process. Does it mean it will check HttpServletRequest.getSession() or just check whether other pages already created this bean or not?

If it does not find the Bean, instantiates it from the class you specify, storing a > reference to it in the new variable.

This actually means that Jsp can associate newly created bean with session using jsp_internal_name_user. There is no any word about how Jsp stores and finds beans in the session.

There is an option to access session objects by using ${sessionScope.user} and that will guarantee that "user" from the Java session object will be get. The same one I put into by myself.

Java EE 5 example "Book Store" access session objects using ${sessionScope.name} approach.

Using just ${user} works. And this is what makes me worry. I would like to see specific sentence in some specification about locate process and whether ${user} must work or it is up to JSP and/or JSTL reference implementation.

A: 

From the documentation:

The <jsp:useBean> element locates or instantiates a JavaBeans component. <jsp:useBean> first attempts to locate an instance of the Bean. If the Bean does not exist, <jsp:useBean> instantiates it from a class or serialized template.

Since "locating" the bean is perfectly allright then we can assume that the bean may be made available by means other than instantiation via <jsp:useBean>. For instance, by creating it in a servlet.

lexicore
+2  A: 

In case of a controller (servlet) which takes care about the model, the jsp:useBean is only useful if the default instance (constructed with the no-arg consturctor) exposes different behaviour/state than a non-existing instance. E.g. if you would like to have a default user name "Unknown User", you would do:

public User {
    this.id = "Unknown User";
}

Else the enduser may face a "Welcome" instead of "Welcome Unknown User" display. In your particular case, you can safely remove it. It's superfluous.

However, I've also seen the argument that it's useful for pure documentation. You could declare "useless" jsp:useBean instances in top of JSP page so that you have an overview which models exactly are been used in the particular JSP page. Although I find it pretty smart, I myself have never had the need for this way of documenting the model in JSP. As per the comments, another arguement is indeed that this way IDE's like IDEA and Eclipse are able to autocomplete bean properties in EL.

Update: as to the locating, it uses PageContext#findAttribute() for that and then uses reflection/javabean introspection to invoke getter methods on it. E.g.

${user.name}

roughly resolves to

out.print(pageContext.findAttribute("user").getName())

Also see the JSP specification and the JSP EL specification.

Update 2: the <jsp:useBean> certainly doesn't use an internal name or so as session attribute prefix. Loop over all session attributes yourself to see the actual keys and values:

<c:forEach items="${sessionScope}" var="entry">
    ${entry.key} = ${entry.value}<br>
</c:forEach>

or in a servlet

for (String name : Collections.list(session.getAttributeNames())) {
   System.out.println(name + " = " + session.getAttribute(name));
}
BalusC
Is there some documentation which explicitly describe the process of the variables resolving in a jsp page?
Mykola Golubyev
Intellij IDEA completes variable fields only in case of the explicit declaration.
Mykola Golubyev
1) You're talking about EL? Check the [JSP EL specification](https://jsp.dev.java.net/spec/jsp-2_1-fr-spec-el.pdf). In a nutshell, it does `PageContext#findAttribute()` to locate attributes in any scope. 2) That's indeed also another argument I've seen before.
BalusC
Thanks for pointing things out. I was referring JSP spec and did not find anything useful there. Looking in EL Spec.
Mykola Golubyev
+1 BTW (padpad)
Pascal Thivent
Could you please point to section where you have found "roughly resolves to..."?
Mykola Golubyev
Well, it's in brain cell # 1875129. No, sorry I'm more telling from >7 years JSP/Servlet experience and knowing how it works "under the hoods". The above example is one which makes the most sense to the JSP/EL-unaware. The EL spec is a bit more abstract than that. `ELResolver` and so on. But the straightforward way (what practically all EL implementers --Sun, Apache, JBoss, etc-- do) is to start with `PageContext#findAttribute()` to find the attribute by name in any of the scopes and then go ahead with resolving using reflection/introspection/etc.
BalusC
So, the usage of the session bean in my question's example is valid?
Mykola Golubyev
It's functionally and technically valid, yes. But it's technically superfluous.
BalusC
I am sorry I still ask questions. But just noticed that even BookStore EE5 example is using "sessionScope.cart" instead of just "cart"
Mykola Golubyev
Check http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html#bnahw. As to the bookstore example, it's just an *explicit* reference to ensure that it doesn't return a "coincidental" `cart` instance in page or request scope (which are scanned *before* the session scope). This is just a "practice", but not necessary.
BalusC
I accidentally put plus again on the answer and it became "score remove" action. I edit your answer just to be able to put scores back. Please undo my changes. Thanks very much for pointing to the text. I was looking in the specs and it was just on the tutorial page.
Mykola Golubyev
+1  A: 

Quoting the JSP spec JSP.5.1

The basic semantic tries to find an existing object using id and scope. If the object is not found it will attempt to create the object using the other attributes.

In other words,

<jsp:useBean id="user" scope="session" class="package.name.User"/>

would translate roughly into java as:

package.name.User user = (package.name.User)session.getAttribute("user");
if (user == null){
  user = new package.name.User();
  session.setAttribute("user", user);
}
evnafets
Hey, glad to see you here :) Your answer is indeed right for the particular `jsp:usebean` line, you only forgot the `session.setAttribute("user", user);` in the `if` block ;)
BalusC
I would like to see the description of "find an existing" process. In fact jsp can store object using "user_jsp_internal" name.
Mykola Golubyev
No, it doesn't. The object is stored with the attribute key as specified in `id`. How else would you be able to access it in plain EL by `${user}` and so on?
BalusC
Because of the current implementation. Why then we have ${scopeSession.user} explicit expression available to use. Please point where did you find that it will store it in the session by using id? I think it is what JSR implementation guys can decide themselves.
Mykola Golubyev
Refer to JSP.5.1.It is all there in black and white.
evnafets