playframework / playframework/playframework
Scala 3 opaque types are not supported as path parameters
- Dominant language
- Scala
- Stars
- 12.6k
- Forks
- 4k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 29
Description
Play Version
3.0.3
API
Scala
Expected Behavior
For an opaque type with PathBindable, e.g.
opaque type TeamName = String
implicit def teamNamePathBindable(using strBinder: PathBindable[String]): PathBindable[TeamName] =
strBinder.transform(TeamName.apply, _.toString())
and a Controller
@Singleton
class TeamsController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
def team(teamName: TeamName): Action[AnyContent] =
Action { OK("Hello " + teamName) }
}
When creating a route with the path bindable, e.g.
GET /teams/:teamName TeamsController.team(teamName: TeamName)
It should generate a Routes file for this endpoint
Actual Behavior
The compiler throws
[error] /conf/app.routes:5:1: model.TeamName is not a class type
[error] GET /teams/:teamName TeamsController.team(teamName: TeamName)
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
Note, this can be implemented when providing the generated routes manually when the HandlerDef. parameterTypes are suppressed:
override def routes: Router.Routes = {
case routeMatch(params@_) =>
call(params.fromPath[TeamName]("teamName", None)) { (teamName) =>
createInvoker(
fakeCall = teamsController.team(fakeValue[TeamName]),
handlerDef = HandlerDef(
classLoader = this.getClass.getClassLoader,
routerPackage = "app",
controller = "TeamsController",
method = "team",
parameterTypes = Seq.empty,//Seq(classOf[TeamName]), // This is where opaque types don't work
verb = "GET",
path = this.prefix + """teams/""" + "$" + """teamName<[^/]+>/team""",
comments = "",
modifiers = Seq.empty
)
).call(teamsController.team(teamName))
}
}
private lazy val routeMatch = Route("GET",
PathPattern(List(StaticPart(this.prefix), StaticPart(this.defaultPrefix), StaticPart("teams/"), DynamicPart("teamName", """[^/]+""", encodeable=true), StaticPart("/team")))
)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the Scala 3 opaque-type route failure using the shown PathBindable, controller, and app.routes examples, then inspect route generation around HandlerDef.parameterTypes. Compare the behavior with open pull request #14177; done means the endpoint generates and compiles without requiring manually generated routes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scala
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100