Skip to content

Commit

Permalink
Deprecate tags, add migration docs
Browse files Browse the repository at this point in the history
  • Loading branch information
richdougherty committed Aug 26, 2016
1 parent 52803ac commit c2ea972
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 3 deletions.
110 changes: 110 additions & 0 deletions documentation/manual/releases/release26/migration26/Migration26.md
Expand Up @@ -153,3 +153,113 @@ libraryDependencies += "org.apache.tomcat" % "tomcat-servlet-api" % "8.0.33"
### Akka Migration

The deprecated static methods `play.libs.Akka.system` and `play.api.libs.concurrent.Akka.system` were removed. Please dependency inject an `ActorSystem` instance for access to the actor system.

### Request tags deprecated, replaced with attributes

In Play each `Request` and `RequestHeader` object carries a map of strings called *tags*. This map can be used to attach extra information to a request. In Play 2.6 request tags have been deprecated. A new alternative to tags, called *attributes*, should be used instead.

Unlike tags, which can only be strings, attributes have types. Attributes are identified by a `TypedKey<T>` object that holds the attribute's type. This means the type system can catch errors in your code. It also means you can attach normal objects to a request, not just strings.

In Play 2.6, tags are still provided and still work. However, tags will be removed in a future version of Play so you should update your existing code to use attributes instead.

Existing Java code:

```java
// Tags have string keys
final String USER_ID = "userId";
...
// Store the User object's id in the tags map
User user = getUser(...);
req.tags.put(USER_ID, Long.toString(user.getId()));
...
// Get the user's id out of the tags map then look up the original User object
User user = getUserById(Long.parseLong(req.tags.get(USER_ID)));
```

Updated Java code:

```java
// Use a key with type User
import play.api.libs.typedmap.TypedKey
final TypedKey<User> USER = TypedKeyFactory.create("user");
...
// Create new copy of the request with the USER attribute added
User user = getUser(...);
Request reqWithUser = req.withAttr(USER, user);
...
// Get the USER attribute from the request
User user = req.attr(USER);
```

Existing Scala code:

```scala
// Tags have string keys
val USER_ID: String = "userId"
...
// Store the User object's id in the tags map
val user: User = getUser(...)
val reqWithUserId = req.copy(tags = req.tags + (USER_ID -> user.id.toString))
...
// Get the user's id out of the tags map then look up the original User object
User user = getUserById(Long.parseLong(reqWithUserId.tags(USER_ID)))
```

Updated Scala code:

```scala
// Use a key with type User
import play.api.libs.typedmap.TypedKey
val User: TypedKey[User] = TypedKey.create("user")
...
// Create new copy of the request with the User attribute added
val user: User = getUser(...)
val reqWithUser = req.withAttr(USER, user)
...
// Get the User attribute from the request
val user: User = req.attr(USER)
```

#### Request Security username property is now an attribute

The Java Request object contains a `username` property which is set when the `Security.Authenticated` annotation is added to a Java action. In Play 2.6 the username property has been deprecated. The username property methods have been updated to store the username in the `Security.USERNAME` attribute. You should update your code to use the `Security.USERNAME` attribute directly. In a future version of Play we will remove the username property.

The reason for this change is that the username property was provided as a special case for the `Security.Authenticated` annotation. Now that we have attributes we don't need a special case anymore.

Existing Java code:

```java
// Set the username
Request reqWithUsername = req.withUsername("admin");
// Get the username
String username = req1.username();
// Set the username with a builder
Request reqWithUsername = new RequestBuilder().username("admin").build();
```

Updated Java code:

```java
import play.mvc.Security.USERNAME;

// Set the username
Request reqWithUsername = req.withAttr(USERNAME, "admin");
// Get the username
String username = req1.attr(USERNAME);
// Set the username with a builder
Request reqWithUsername = new RequestBuilder().putAttr(USERNAME, "admin").build();
```

#### Router tags are now attributes

If you used any of the `Router.Tags.*` tags, you should change your code to use the new `Router.HandlerDefAttr` attribute instead. The existing tags are still available, but are deprecated and will be removed in a future version of Play.

The attribute contains a `HandlerDef` object that contains all the information that is currently in the tags. The relationship between a `HandlerDef` object and its tags is as follows:

```scala
RoutePattern -> handlerDef.path
RouteVerb -> handlerDef.verb
RouteController -> handlerDef.controller
RouteActionMethod -> handlerDef.method
RouteComments -> handlerDef.comments
```
10 changes: 7 additions & 3 deletions framework/src/play/src/main/java/play/mvc/Http.java
Expand Up @@ -14,11 +14,8 @@
import play.api.libs.json.JsValue;
import play.api.libs.typedmap.TypedEntry;
import play.api.libs.typedmap.TypedKey;
import play.api.libs.typedmap.TypedKeyFactory;
import play.api.libs.typedmap.TypedMap;
import play.api.mvc.Headers;
import play.core.j.JavaHelpers;
import play.core.j.JavaHelpers$;
import play.core.j.JavaParsers;
import play.core.system.RequestIdProvider;
import play.i18n.Lang;
Expand Down Expand Up @@ -672,7 +669,9 @@ public static interface RequestHeader {

/**
* @return the tags for the request
* @deprecated Use <code>attr</code>, <code>withAttr</code>, etc.
*/
@Deprecated
Map<String, String> tags();

/**
Expand Down Expand Up @@ -1061,6 +1060,7 @@ void putAttrs(TypedEntry<?> ...entries) {

/**
* @return the tags for the request
* @deprecated Use <code>attr</code> or <code>getAttr</code> instead.
*/
public Map<String, String> tags() {
return tags;
Expand All @@ -1069,7 +1069,9 @@ public Map<String, String> tags() {
/**
* @param tags overwrites the tags for this request
* @return the builder instance
* @deprecated Use <code>putAttrs</code> instead.
*/
@Deprecated
public RequestBuilder tags(Map<String, String> tags) {
this.tags = tags;
return this;
Expand All @@ -1080,7 +1082,9 @@ public RequestBuilder tags(Map<String, String> tags) {
* @param key the key for the tag
* @param value the value for the tag
* @return the builder
* @deprecated Use <code>putAttr</code> instead.
*/
@Deprecated
public RequestBuilder tag(String key, String value) {
tags.put(key, value);
return this;
Expand Down
Expand Up @@ -25,6 +25,7 @@ trait RequestHeader {
/**
* The request Tags.
*/
@deprecated("Use attributes instead (e.g. attr(), getAttr(), withAttr(), etc)", "2.6.0")
def tags: Map[String, String]

/**
Expand Down
Expand Up @@ -7,6 +7,10 @@ import play.api.libs.typedmap.{ TypedEntry, TypedKey }

/**
* Wrap an existing request. Useful to extend a request.
*
* If you need to add extra values to a request, you could consider
* using request attributes instead. See the `attr`, `withAttr`, etc
* methods.
*/
class WrappedRequest[+A](request: Request[A]) extends Request[A] {
override def id = request.id
Expand Down

0 comments on commit c2ea972

Please sign in to comment.