Skip to content

Commit

Permalink
Merge pull request #14 from dwickern/play-2.9
Browse files Browse the repository at this point in the history
add support for Play 2.9
  • Loading branch information
dwickern committed Nov 1, 2023
2 parents 0313777 + e54e224 commit 65f86a5
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 89 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ jobs:
matrix:
play-version: [ 2.7.3, 2.7.9, 2.8.0, 2.8.7, 2.8.8, 2.8.20 ]
java-version: [ 8, 11 ]
include:
- play-version: 2.9.0
java-version: 11

steps:
- name: Checkout
Expand Down
33 changes: 32 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ ThisBuild / organization := "com.github.dwickern"

lazy val play27 = ConfigAxis("play27", "play2.7")
lazy val play28 = ConfigAxis("play28", "play2.8")
lazy val play29 = ConfigAxis("play29", "play2.9")

lazy val scala212 = "2.12.13"
lazy val scala213 = "2.13.4"
Expand Down Expand Up @@ -51,6 +52,8 @@ lazy val swagger = (projectMatrix in file("."))
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play" % "2.7.3",
"com.typesafe.play" %% "routes-compiler" % "2.7.3",
"com.typesafe.play" %% "play-test" % "2.7.3" % Test,
"com.typesafe.play" %% "play-specs2" % "2.7.3" % Test,
"io.swagger" % "swagger-core" % "1.5.24",
"io.swagger" %% "swagger-scala-module" % "1.0.6",
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.10",
Expand All @@ -66,13 +69,33 @@ lazy val swagger = (projectMatrix in file("."))
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play" % "2.8.0",
"com.typesafe.play" %% "routes-compiler" % "2.8.0",
"com.typesafe.play" %% "play-test" % "2.8.0" % Test,
"com.typesafe.play" %% "play-specs2" % "2.8.0" % Test,
"io.swagger" % "swagger-core" % "1.6.1",
"io.swagger" %% "swagger-scala-module" % "1.0.6", // FIXME: no version supports jackson 2.10
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.10.5",
"com.typesafe.play" %% "play-ebean" % "6.0.0" % Test,
)
)
)
.customRow(
scalaVersions = Seq(scala213),
axisValues = Seq(play29, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "2.9",
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play" % "2.9.0",
"com.typesafe.play" %% "play-routes-compiler" % "2.9.0",
"com.typesafe.play" %% "play-test" % "2.9.0" % Test,
"com.typesafe.play" %% "play-specs2" % "2.9.0" % Test,
"io.swagger" % "swagger-core" % "1.6.11",
"io.swagger" %% "swagger-scala-module" % "1.0.6",
"javax.xml.bind" % "jaxb-api" % "2.3.1",
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.14.2",
"com.typesafe.play" %% "play-ebean" % "7.0.0-RC2" % Test,
)
)
)

/**
* Run tests using a specific Play version
Expand All @@ -81,7 +104,15 @@ lazy val swagger = (projectMatrix in file("."))
* sbt "testPlayVersion 2.8.8"
*/
lazy val testPlayVersionCommand = Command.single("testPlayVersion") { case (state, playVersion) =>
val projectAxis = if (VersionNumber(playVersion).matchesSemVer(SemanticSelector("2.7.x"))) play27 else play28
val matrix = Map(
SemanticSelector("2.7.x") -> play27,
SemanticSelector("2.8.x") -> play28,
SemanticSelector("2.9.x") -> play29,
)
val projectAxis = matrix
.collectFirst { case (sel, axis) if VersionNumber(playVersion).matchesSemVer(sel) => axis }
.getOrElse { throw new Exception(s"Unsupported Play version: $playVersion") }

swagger.finder(projectAxis, VirtualAxis.jvm).get.foldLeft(state) { case (state, project) =>
/** Extra dependencies needed for Play 2.8.8 */
val play288extras = if (VersionNumber(playVersion).matchesSemVer(SemanticSelector(">=2.8.8"))) {
Expand Down
94 changes: 6 additions & 88 deletions src/main/scala/controllers/ApiHelpController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,91 +16,37 @@

package controllers

import java.io.StringWriter

import akka.util.ByteString
import io.swagger.core.filter.SpecFilter
import io.swagger.models.Swagger
import io.swagger.util.Json
import javax.inject.Inject
import javax.xml.bind.annotation._
import play.api.Logger
import play.api.http.ContentTypes
import play.api.mvc._
import play.modules.swagger.SwaggerPlugin

import scala.jdk.CollectionConverters._

object ErrorResponse {
val ERROR = 1
val WARNING = 2
val INFO = 3
val OK = 4
val TOO_BUSY = 5
}

class ErrorResponse(@XmlElement var code: Int, @XmlElement var message: String) {
def this() = this(0, null)

@XmlTransient
def getCode: Int = code

def setCode(code: Int) = this.code = code

def getType: String = code match {
case ErrorResponse.ERROR => "error"
case ErrorResponse.WARNING => "warning"
case ErrorResponse.INFO => "info"
case ErrorResponse.OK => "ok"
case ErrorResponse.TOO_BUSY => "too busy"
case _ => "unknown"
}

def getMessage: String = message

def setMessage(message: String) = this.message = message
}

class ApiHelpController @Inject() (components: ControllerComponents, val swaggerPlugin: SwaggerPlugin)
extends AbstractController(components) with SwaggerBaseApiController {

def getResources = Action { implicit request =>
val host: String = swaggerPlugin.config.host
val resourceListing: Swagger = getResourceListing(host)
val response: String = returnXml(request) match {
case true => toXmlString(resourceListing)
case false => toJsonString(resourceListing)
}
returnValue(request, response)
respond(resourceListing)
}

def getResource(path: String) = Action { implicit request =>
val host: String = swaggerPlugin.config.host
val apiListing: Swagger = getApiListing(path, host)
val response: String = returnXml(request) match {
case true => toXmlString(apiListing)
case false => toJsonString(apiListing)
}
Option(response) match {
case Some(help) => returnValue(request, help)
case None =>
val msg = new ErrorResponse(500, "api listing for path " + path + " not found")
Logger("swagger").error(msg.message)
if (returnXml(request)) {
InternalServerError(ByteString(toXmlString(msg))).as(XML(Codec.utf_8))
} else {
InternalServerError(ByteString(toJsonString(msg))).as(JSON)
}
}
respond(apiListing)
}
}

trait SwaggerBaseApiController {

def swaggerPlugin: SwaggerPlugin

protected def returnXml(request: Request[_]) = request.path.contains(".xml")

protected val AccessControlAllowOrigin = ("Access-Control-Allow-Origin", "*")

/**
Expand Down Expand Up @@ -149,37 +95,9 @@ trait SwaggerBaseApiController {
clone
}

// TODO: looks like this is broken for anything other than strings
def toXmlString(data: Any): String = {
if (data.getClass.equals(classOf[String])) {
data.asInstanceOf[String]
} else {
val stringWriter = new StringWriter()
stringWriter.toString
}
}

protected def XmlResponse(data: Any) = {
Results.Ok(toXmlString(data)).as(ContentTypes.XML(Codec.utf_8))
}

protected def returnValue(request: Request[_], obj: Any): Result = {
val response = returnXml(request) match {
case true => XmlResponse(obj)
case false => JsonResponse(obj)
}
response.withHeaders(AccessControlAllowOrigin)
}

def toJsonString(data: Any): String = {
if (data.getClass.equals(classOf[String])) {
data.asInstanceOf[String]
} else {
Json.pretty(data.asInstanceOf[AnyRef])
}
}

protected def JsonResponse(data: Any): Result = {
Results.Ok(ByteString(toJsonString(data))).as(ContentTypes.JSON)
protected def respond(spec: Swagger): Result = {
Results.Ok(Json.pretty(spec))
.as(ContentTypes.JSON)
.withHeaders(AccessControlAllowOrigin)
}
}
21 changes: 21 additions & 0 deletions src/test/scala/PlayApiHelpControllerSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import controllers.ApiHelpController
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable._
import play.api.libs.json.JsString
import play.api.test.Helpers._
import play.api.test.{FakeRequest, Helpers, WithApplication}
import play.modules.swagger._

class PlayApiHelpControllerSpec(implicit ee: ExecutionEnv) extends Specification {

"ApiHelpController" should {
"return the swagger specification" in new WithApplication {
val swaggerPlugin = new SwaggerPluginImpl(app.environment, app.configuration)
val controller = new ApiHelpController(Helpers.stubControllerComponents(), swaggerPlugin)
val result = controller.getResources(FakeRequest("GET", "/swagger.json"))
result.map(_.header.status) must beEqualTo (200).await
val body = contentAsJson(result)
(body \ "swagger").get must beEqualTo (JsString("2.0"))
}
}
}

0 comments on commit 65f86a5

Please sign in to comment.