[Play 2.7 Java] Is it a good idea for me to create my own ThreadLocal request scoped context?

We are running Play 2.6 right now, and our application relies on the ThreadLocal<Http.Context> and Http.Context.args being a mutable Map, and the way cookies currently work, i.e. Http.Context.current().response().setCookie(...).

So here are the 2 obvious problems we are facing with the 2.7 upgrade:

  1. The ThreadLocal is deprecated and Http.Request needs to be passed along manually.
  2. The Javadoc for Http.Context.args simply says that you use Http.Request.attrs() instead, but the problem is that attrs is immutable.

So here’s the current solution I came up with. I’m creating a global public static final ThreadLocal<MyRequestContext>, and it’s initialized at the beginning of a custom play.mvc.Filter, and then it’s automatically passed along with a custom Executor. MyRequestContext is mutable and, in addition to storing what we used to store in args, I’m also using it to store all the cookies I want to add/discard, and then they are processed in the end by the same play.mvc.Filter.

So far my solution works pretty well. What I’m asking here is whether this is considered acceptable as a long-term solution. I obviously don’t want this to stop working in the next Play update. Also, is there a more straightforward way in Play 2.7 to do mutable request scoped context? I think this is a reasonable thing to ask for since most other web frameworks, including Play 2.6, support it.

Thanks!

Hey @slisaasquatch,

Of course, it depends on your application, but we decide to deprecate Http.Context because we don’t believe the thread-local model is a good fit for Play. It is hard to test, you need to maintain it carefully, and it is not clear that you are accessing Request data when using APIs such Http.Current.changeLang. Some of the APIs are also confusing and misplaced. setCookie for example should be part of Result instead of being backed by a thread local(!) in Http.Context.
Finally, you may be interested in this issue:

My suggestion there was to add a mutable attribute to the request, but still, it looks like a step to transition away from Http.Context instead of a final solution. We are doing our best to ensure this transition is well documented, so if you haven’t seen this page, I recommend to take a look:

Best.

Thanks for your suggestion. I think I may actually try adding mutable stuff to attrs. So is native support for mutable request attributes something you guys are looking at?

No. The APIs are being designed to transform the request, result, cookies, session, flash etc. and pass them forward. But as I said at the issue, it still may need some feedback and polishing to be more convenient.

What kind of mutation are you doing now? Can you better explain your use case so that we can see how to make it happen using the new APIs?

Best.

One example of the things that make it hard for us to move to the immutable APIs is GraphQL. We are using GraphQL Java and we are currently (on Play 2.6) passing an instance of Http.Context into the GraphQL context, and then the Http.Context gets modified deep inside the GraphQL mutations. So in this case the action/controller cannot predict what the mutations are going to be and I just don’t see a straightforward way of doing action composition.

You can create your own mutable Context and modify that, and call a sync method to pull and synchronize the two.

This would also let you implement your local context as a list of commands, so if you add a cookie, you could record that as addCookie() internally and keep track of which mutations were applied in what order.