Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added "safer" example, changed MyState to ShoppingCart for consistency

...

But how to avoid creating it? Simply checking ("myState shoppingCart!= null") will force the creation of the SSO and the session to store it in.

Instead, create a second field with a matching name but with "Exists" appended:

Code Block
java
java
  private boolean myStateExistsshoppingCartExists;

This companion field is used to see if the SSO already exists. It is not annotated; it is located by name naming convention ("Exists" is appended to the name of the field storing the SSO). It must be type boolean and must be a private instance variable. Tapestry will automatically set this variable to true when the SSO is created, so you can check it to see if the SSO already exists.

Alternately, you may allow for the state being null:

Code Block
java
java
  @SessionState(create=false)
  private MyStateShoppingCart myStateshoppingCart;

In this case, the myState shoppingCart field will be null if the MyState ShoppingCart SSO does not exist, but will be non-null if it has been created (either by assigning a value to the field, or by a different SSO field where create is true).

...

Code Block
java
java
  public void contributeApplicationStateManager(MappedConfiguration<Class, ApplicationStateContribution> configuration)
  {
    ApplicationStateCreator<MyState> creator = new ApplicationStateCreator<MyState>ApplicationStateCreator<ShoppingCart>()
    {
      public MyStateShoppingCart create()
      {
        return new MyStateShoppingCart(new Date());
      }
    };
  
    configuration.add(MyStateShoppingCart.class, new ApplicationStateContribution("session", creator));
  }

Here, we have an SSO type of MyStateShoppingCart, and we're providing a creator for it. We've dolled the creator up with some generic types, but that isn't essential.

...

Since 5.2 this can be accomplished just by annotating a page or component property with @SessionAttribute. This annotation is used to map a property of a page or component to value stored in session. Unlike Session State Objects, the name (not the type) of the annotated property is used as the name of the session attribute to look for.

Code Block
titleThe New Way

public class Page {
    @SessionAttribute
    private User loggedInUserName;
}

You can also provide a name using the annotation's value parameter.:

title
Code Block
The New Way
public class Page {
    @SessionAttribute("loggedInUserName")
    private User loggedInUserNameuserName;
}

Pitfalls

As with SSOs, when using Session Attributes you are creating a session-wide data storage area that has the serious possibility of data collisions, not just within your application but with other modules/libraries. To avoid problems, you should qualify the session attribute name with a package-like naming convention. For example, use something like "com.mycompany.myapp.username" instead of just "username".

It's best to define the session attribute name as constant, and use that in the annotation's value parameter, rather then defaulting to the instance variable name. This will help prevent subtle runtime errors due to misspellings. For example:

Code Block
titleThe Safer Way

public static final String USER_NAME_SESSION_ATTRIBUTE = "com.example.shoppingapp.username";

...

public class Page {
    @SessionAttribute(USER_NAME_SESSION_ATTRIBUTE)
    private User userName;
}