...
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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
| ||||
@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 | ||||
---|---|---|---|---|
| ||||
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 | ||
---|---|---|
| ||
public class Page {
@SessionAttribute
private User loggedInUserName;
}
|
You can also provide a name using the annotation's value
parameter.:
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 | ||
---|---|---|
| ||
public static final String USER_NAME_SESSION_ATTRIBUTE = "com.example.shoppingapp.username"; ... public class Page { @SessionAttribute(USER_NAME_SESSION_ATTRIBUTE) private User userName; } |