{"action":"created","comment":{"url":"https://api.github.com/repos/playframework/playframework/pulls/comments/28573553","id":28573553,"diff_hunk":"@@ -5,53 +5,96 @@ This page highlights the new features of Play 2.4. If you want learn about the c\n \n ## Dependency Injection\n \n-- TODO(jroper)\n+Play now supports dependency injection out of the box.\n \n-## Embeddable Router\n+### Motivation\n \n-- TODO(jroper)\n-- Java - https://github.com/playframework/playframework/blob/master/documentation/manual/working/javaGuide/advanced/embedding/JavaEmbeddingPlay.md\n-- Scala - https://github.com/playframework/playframework/blob/master/documentation/manual/working/scalaGuide/advanced/embedding/ScalaEmbeddingPlay.md\n+A long term strategy for Play is to remove Play's dependence on global state.  Play currently stores a reference to the current application in a static variable, and then uses this variable in many places throughout its codebase.  Removing this has the following advantages:\n \n-## Logging enhancements\n+* Applications become easier to test and components become easier to mock.\n+* More interesting deployment scenarios are possible, such as multiple Play instances in a single JVM, or embedding a lightweight Play application.\n+* The application lifecycle becomes easier to follow and reason about.\n \n-- TODO(jroper): jroper made some good changes here with better support for logback\n-- Log messages generated by Play can now be configured on a per-class basis as opposed to previously needing to change the log level for all Play log messages.\n+Removing Play's global state is however a big task that will require some disruptive changes to the way Play applications are written.  The approach we are taking to do this is to do as much as possible in Play 2.4 while maintaining backwards compatibility.  For a time, many of Play's APIs will support both methods that rely on require global state and methods that don't rely on global state, allowing you to migrate your application to not depend on global state incrementally, rather than all at once when you uprgade to Play 2.4.\n \n-## Java 8 support\n+The first step to removing global state is to make it such that Play components have their dependencies provided to them, rather than looking them up statically.  This means providing out of the box support for dependency injection.\n \n-- JSON handling now supports Java 8 temporal values such as Instant, LocalDateTime, and LocalDate.\n-- The Play documentation now shows code examples using Java 8 syntax for callables. As an example, here's how some code has changed.\n+### Approach\n \n-Before:\n+In the Java ecosystem, the approach to dependency injection is generally well agreed upon in [JSR 330](https://jcp.org/en/jsr/detail?id=330), but the right implementation is widely debated, with many existing competing implementations such as Guice, Spring and JEE itself.\n \n-    return promise(new Function0<Integer>() {\n-      public Integer apply() {\n-        return longComputation();\n-      }\n-    }).map(new Function<Integer,Result>() {\n-      public Result apply(Integer i) {\n-        return ok(\"Got \" + i);\n-      }\n-    });\n+In the Scala ecosystem, the approach to dependency injection is not generally agreed upon, with many competing compile time and runtime dependency injection approaches out there.\n \n+Play's philosophy in providing a dependency injection solution is to be unopinionated in what approaches we allow, but to be opinionated to the approach that we document and provide out of the box.  For this reason, we have provided the following:\n \n-After:\n+* An implementation that uses [Guice](https://code.google.com/p/google-guice/) out of the box\n+* An abstraction that allows other JSR 330 implementations to be plugged in\n+* All Play components can be instantiated using plain constructors or factory methods\n+* Traits that instantiate Play components that can be mixed together in a cake pattern like style to assist with compile time dependency injection\n+\n+You can read more about Play's dependency injection support for [[Java|JavaDepnedencyInjection]] and [[Scala|ScalaDependencyInjection]].\n+\n+## Testing\n+\n+One of the biggest advantages of introducing dependency injection to Play is that many parts of Play can now be much easier to test.  Play now provides a number of APIs to assist in mocking and overriding components, as well as being able to test interactions with Play components in isolation from the rest of your Play application.\n+\n+You can read about these new APIs here:\n+\n+* Configuring Guice components in [[Java|JavaTestingWithGuice]] and [[Scala|ScalaTestingWithGuice]]\n+* Testing database access code in [[Java|JavaTestingWithDatabases]] and [[Scala|ScalaTestingWithDatabases]]\n+* Testing web service client code in [[Java|JavaTestingWebServiceClients]] and [[Scala|ScalaTestingWebServiceClients]]\n+\n+## Embedding Play\n+\n+It is now straight forward to embed a Play application.  Play 2.4 provides both APIs to start and stop a Play server, as well as routing DSLs for Java and Scala so that routes can be embedded directly in code.\n+\n+In Java, see [[Embedding Play|JavaEmbeddingPlay]] as well as information about the [[Routing DSL|JavaRoutingDSL]].\n+\n+In Scala, see [[Embedding Play|ScalaEmbeddingPlay]] as well as information about the [[String Interpolating Routing DSL|ScalaSirdRouting]].","path":"documentation/manual/releases/Highlights24.md","position":71,"original_position":71,"commit_id":"e5feb3b7981e1cc87baee11d2c68065b277bd04d","original_commit_id":"e5feb3b7981e1cc87baee11d2c68065b277bd04d","user":{"login":"julienrf","id":332812,"avatar_url":"https://avatars.githubusercontent.com/u/332812?v=3","gravatar_id":"","url":"https://api.github.com/users/julienrf","html_url":"https://github.com/julienrf","followers_url":"https://api.github.com/users/julienrf/followers","following_url":"https://api.github.com/users/julienrf/following{/other_user}","gists_url":"https://api.github.com/users/julienrf/gists{/gist_id}","starred_url":"https://api.github.com/users/julienrf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/julienrf/subscriptions","organizations_url":"https://api.github.com/users/julienrf/orgs","repos_url":"https://api.github.com/users/julienrf/repos","events_url":"https://api.github.com/users/julienrf/events{/privacy}","received_events_url":"https://api.github.com/users/julienrf/received_events","type":"User","site_admin":false},"body":"Just curiosity: what happens if your embedded application uses an API that relies on `play.api.Play.maybeApplication`?","created_at":"2015-04-17T06:59:22Z","updated_at":"2015-04-17T06:59:22Z","html_url":"https://github.com/playframework/playframework/pull/4257#discussion_r28573553","pull_request_url":"https://api.github.com/repos/playframework/playframework/pulls/4257","_links":{"self":{"href":"https://api.github.com/repos/playframework/playframework/pulls/comments/28573553"},"html":{"href":"https://github.com/playframework/playframework/pull/4257#discussion_r28573553"},"pull_request":{"href":"https://api.github.com/repos/playframework/playframework/pulls/4257"}}},"pull_request":{"url":"https://api.github.com/repos/playframework/playframework/pulls/4257","id":33513772,"html_url":"https://github.com/playframework/playframework/pull/4257","diff_url":"https://github.com/playframework/playframework/pull/4257.diff","patch_url":"https://github.com/playframework/playframework/pull/4257.patch","issue_url":"https://api.github.com/repos/playframework/playframework/issues/4257","number":4257,"state":"open","locked":false,"title":"Updated 2.4 highlights","user":{"login":"jroper","id":105833,"avatar_url":"https://avatars.githubusercontent.com/u/105833?v=3","gravatar_id":"","url":"https://api.github.com/users/jroper","html_url":"https://github.com/jroper","followers_url":"https://api.github.com/users/jroper/followers","following_url":"https://api.github.com/users/jroper/following{/other_user}","gists_url":"https://api.github.com/users/jroper/gists{/gist_id}","starred_url":"https://api.github.com/users/jroper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jroper/subscriptions","organizations_url":"https://api.github.com/users/jroper/orgs","repos_url":"https://api.github.com/users/jroper/repos","events_url":"https://api.github.com/users/jroper/events{/privacy}","received_events_url":"https://api.github.com/users/jroper/received_events","type":"User","site_admin":false},"body":null,"created_at":"2015-04-17T04:28:04Z","updated_at":"2015-04-17T06:59:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8b15e1f01f81507b67a81c4cc5e0dd1f9b4d0a8b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/playframework/playframework/pulls/4257/commits","review_comments_url":"https://api.github.com/repos/playframework/playframework/pulls/4257/comments","review_comment_url":"https://api.github.com/repos/playframework/playframework/pulls/comments{/number}","comments_url":"https://api.github.com/repos/playframework/playframework/issues/4257/comments","statuses_url":"https://api.github.com/repos/playframework/playframework/statuses/e5feb3b7981e1cc87baee11d2c68065b277bd04d","head":{"label":"jroper:24highlights","ref":"24highlights","sha":"e5feb3b7981e1cc87baee11d2c68065b277bd04d","user":{"login":"jroper","id":105833,"avatar_url":"https://avatars.githubusercontent.com/u/105833?v=3","gravatar_id":"","url":"https://api.github.com/users/jroper","html_url":"https://github.com/jroper","followers_url":"https://api.github.com/users/jroper/followers","following_url":"https://api.github.com/users/jroper/following{/other_user}","gists_url":"https://api.github.com/users/jroper/gists{/gist_id}","starred_url":"https://api.github.com/users/jroper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jroper/subscriptions","organizations_url":"https://api.github.com/users/jroper/orgs","repos_url":"https://api.github.com/users/jroper/repos","events_url":"https://api.github.com/users/jroper/events{/privacy}","received_events_url":"https://api.github.com/users/jroper/received_events","type":"User","site_admin":false},"repo":{"id":5479103,"name":"playframework","full_name":"jroper/playframework","owner":{"login":"jroper","id":105833,"avatar_url":"https://avatars.githubusercontent.com/u/105833?v=3","gravatar_id":"","url":"https://api.github.com/users/jroper","html_url":"https://github.com/jroper","followers_url":"https://api.github.com/users/jroper/followers","following_url":"https://api.github.com/users/jroper/following{/other_user}","gists_url":"https://api.github.com/users/jroper/gists{/gist_id}","starred_url":"https://api.github.com/users/jroper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jroper/subscriptions","organizations_url":"https://api.github.com/users/jroper/orgs","repos_url":"https://api.github.com/users/jroper/repos","events_url":"https://api.github.com/users/jroper/events{/privacy}","received_events_url":"https://api.github.com/users/jroper/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jroper/playframework","description":"Play framework 2.0","fork":true,"url":"https://api.github.com/repos/jroper/playframework","forks_url":"https://api.github.com/repos/jroper/playframework/forks","keys_url":"https://api.github.com/repos/jroper/playframework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jroper/playframework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jroper/playframework/teams","hooks_url":"https://api.github.com/repos/jroper/playframework/hooks","issue_events_url":"https://api.github.com/repos/jroper/playframework/issues/events{/number}","events_url":"https://api.github.com/repos/jroper/playframework/events","assignees_url":"https://api.github.com/repos/jroper/playframework/assignees{/user}","branches_url":"https://api.github.com/repos/jroper/playframework/branches{/branch}","tags_url":"https://api.github.com/repos/jroper/playframework/tags","blobs_url":"https://api.github.com/repos/jroper/playframework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jroper/playframework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jroper/playframework/git/refs{/sha}","trees_url":"https://api.github.com/repos/jroper/playframework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jroper/playframework/statuses/{sha}","languages_url":"https://api.github.com/repos/jroper/playframework/languages","stargazers_url":"https://api.github.com/repos/jroper/playframework/stargazers","contributors_url":"https://api.github.com/repos/jroper/playframework/contributors","subscribers_url":"https://api.github.com/repos/jroper/playframework/subscribers","subscription_url":"https://api.github.com/repos/jroper/playframework/subscription","commits_url":"https://api.github.com/repos/jroper/playframework/commits{/sha}","git_commits_url":"https://api.github.com/repos/jroper/playframework/git/commits{/sha}","comments_url":"https://api.github.com/repos/jroper/playframework/comments{/number}","issue_comment_url":"https://api.github.com/repos/jroper/playframework/issues/comments{/number}","contents_url":"https://api.github.com/repos/jroper/playframework/contents/{+path}","compare_url":"https://api.github.com/repos/jroper/playframework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jroper/playframework/merges","archive_url":"https://api.github.com/repos/jroper/playframework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jroper/playframework/downloads","issues_url":"https://api.github.com/repos/jroper/playframework/issues{/number}","pulls_url":"https://api.github.com/repos/jroper/playframework/pulls{/number}","milestones_url":"https://api.github.com/repos/jroper/playframework/milestones{/number}","notifications_url":"https://api.github.com/repos/jroper/playframework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jroper/playframework/labels{/name}","releases_url":"https://api.github.com/repos/jroper/playframework/releases{/id}","created_at":"2012-08-20T09:08:58Z","updated_at":"2014-09-03T06:49:35Z","pushed_at":"2015-04-17T04:34:11Z","git_url":"git://github.com/jroper/playframework.git","ssh_url":"git@github.com:jroper/playframework.git","clone_url":"https://github.com/jroper/playframework.git","svn_url":"https://github.com/jroper/playframework","homepage":"http://www.playframework.org/","size":74414,"stargazers_count":6,"watchers_count":6,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":0,"forks":2,"open_issues":0,"watchers":6,"default_branch":"master"}},"base":{"label":"playframework:master","ref":"master","sha":"22700f54a8dda2b098f63505e1fda0d16edfb66e","user":{"login":"playframework","id":319107,"avatar_url":"https://avatars.githubusercontent.com/u/319107?v=3","gravatar_id":"","url":"https://api.github.com/users/playframework","html_url":"https://github.com/playframework","followers_url":"https://api.github.com/users/playframework/followers","following_url":"https://api.github.com/users/playframework/following{/other_user}","gists_url":"https://api.github.com/users/playframework/gists{/gist_id}","starred_url":"https://api.github.com/users/playframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/playframework/subscriptions","organizations_url":"https://api.github.com/users/playframework/orgs","repos_url":"https://api.github.com/users/playframework/repos","events_url":"https://api.github.com/users/playframework/events{/privacy}","received_events_url":"https://api.github.com/users/playframework/received_events","type":"Organization","site_admin":false},"repo":{"id":2340549,"name":"playframework","full_name":"playframework/playframework","owner":{"login":"playframework","id":319107,"avatar_url":"https://avatars.githubusercontent.com/u/319107?v=3","gravatar_id":"","url":"https://api.github.com/users/playframework","html_url":"https://github.com/playframework","followers_url":"https://api.github.com/users/playframework/followers","following_url":"https://api.github.com/users/playframework/following{/other_user}","gists_url":"https://api.github.com/users/playframework/gists{/gist_id}","starred_url":"https://api.github.com/users/playframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/playframework/subscriptions","organizations_url":"https://api.github.com/users/playframework/orgs","repos_url":"https://api.github.com/users/playframework/repos","events_url":"https://api.github.com/users/playframework/events{/privacy}","received_events_url":"https://api.github.com/users/playframework/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/playframework/playframework","description":"Play Framework","fork":false,"url":"https://api.github.com/repos/playframework/playframework","forks_url":"https://api.github.com/repos/playframework/playframework/forks","keys_url":"https://api.github.com/repos/playframework/playframework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/playframework/playframework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/playframework/playframework/teams","hooks_url":"https://api.github.com/repos/playframework/playframework/hooks","issue_events_url":"https://api.github.com/repos/playframework/playframework/issues/events{/number}","events_url":"https://api.github.com/repos/playframework/playframework/events","assignees_url":"https://api.github.com/repos/playframework/playframework/assignees{/user}","branches_url":"https://api.github.com/repos/playframework/playframework/branches{/branch}","tags_url":"https://api.github.com/repos/playframework/playframework/tags","blobs_url":"https://api.github.com/repos/playframework/playframework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/playframework/playframework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/playframework/playframework/git/refs{/sha}","trees_url":"https://api.github.com/repos/playframework/playframework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/playframework/playframework/statuses/{sha}","languages_url":"https://api.github.com/repos/playframework/playframework/languages","stargazers_url":"https://api.github.com/repos/playframework/playframework/stargazers","contributors_url":"https://api.github.com/repos/playframework/playframework/contributors","subscribers_url":"https://api.github.com/repos/playframework/playframework/subscribers","subscription_url":"https://api.github.com/repos/playframework/playframework/subscription","commits_url":"https://api.github.com/repos/playframework/playframework/commits{/sha}","git_commits_url":"https://api.github.com/repos/playframework/playframework/git/commits{/sha}","comments_url":"https://api.github.com/repos/playframework/playframework/comments{/number}","issue_comment_url":"https://api.github.com/repos/playframework/playframework/issues/comments{/number}","contents_url":"https://api.github.com/repos/playframework/playframework/contents/{+path}","compare_url":"https://api.github.com/repos/playframework/playframework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/playframework/playframework/merges","archive_url":"https://api.github.com/repos/playframework/playframework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/playframework/playframework/downloads","issues_url":"https://api.github.com/repos/playframework/playframework/issues{/number}","pulls_url":"https://api.github.com/repos/playframework/playframework/pulls{/number}","milestones_url":"https://api.github.com/repos/playframework/playframework/milestones{/number}","notifications_url":"https://api.github.com/repos/playframework/playframework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/playframework/playframework/labels{/name}","releases_url":"https://api.github.com/repos/playframework/playframework/releases{/id}","created_at":"2011-09-07T09:24:08Z","updated_at":"2015-04-17T02:07:47Z","pushed_at":"2015-04-17T04:34:12Z","git_url":"git://github.com/playframework/playframework.git","ssh_url":"git@github.com:playframework/playframework.git","clone_url":"https://github.com/playframework/playframework.git","svn_url":"https://github.com/playframework/playframework","homepage":"http://www.playframework.com/","size":123524,"stargazers_count":6089,"watchers_count":6089,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2148,"mirror_url":null,"open_issues_count":195,"forks":2148,"open_issues":195,"watchers":6089,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/playframework/playframework/pulls/4257"},"html":{"href":"https://github.com/playframework/playframework/pull/4257"},"issue":{"href":"https://api.github.com/repos/playframework/playframework/issues/4257"},"comments":{"href":"https://api.github.com/repos/playframework/playframework/issues/4257/comments"},"review_comments":{"href":"https://api.github.com/repos/playframework/playframework/pulls/4257/comments"},"review_comment":{"href":"https://api.github.com/repos/playframework/playframework/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/playframework/playframework/pulls/4257/commits"},"statuses":{"href":"https://api.github.com/repos/playframework/playframework/statuses/e5feb3b7981e1cc87baee11d2c68065b277bd04d"}}}}