Play Framework can't import play-json implicit reader & writer - scala

I have a controller in Play Framework (2.5.4) managed by sbt.
userController.scala
package controllers
// import models.User
import com.neruti.User
import play.api._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.functional.syntax._
import pdi.jwt._
import pdi.jwt.{JwtPlayImplicits, JwtSession}
import play.api.mvc.Controller
import java.time.LocalDate
import java.util.UUID
class UserProfileController extends Controller with JwtPlayImplicits {
def putUserProfile = Action(parse.json) {request =>
val userProfile: JsResult[User] = request.body.validate[User]
userProfile.map {
case user:User => Ok("Its good")
}.recoverTotal{
e=>BadRequest("Detected error" + JsError.toFlatJson(e))
}
}
}
Below is User model in another separate module(core) managed by Maven. A multi-module maven pattern.
User.scala
package com.neruti
import play.api.libs.json._
import play.api.data.validation.ValidationError
import play.api.libs.functional.syntax._
case class User(
username: String,
email: Option[String] = None
)
object User {
implicit val userReads: Reads[User] =(
(__ \ "username").read[String] and
(__ \ "email").readNullable[String]
)(User.apply _)
implicit val userWrites: Writes[User] =(
(__ \ "username").write[String] and
(__ \ "email").writeNullable[String]
)(unlift (User.unapply))
}
Issue is inside the userController.scala, it can't see implicit JSON reader&writer in scope.
userController.scala:44: No Json deserializer found for type com.neruti.User. Try to implement an implicit Reads or Format for this type.
[error] val userProfile: JsResult[User] = request.body.validate[User]
Did import com.neruti.User._, doesn't import implicit methods.
However, if I uncommented import models.User, using models package inside play, it works.
Any advice is much appreciated.

For some reason I can't comprehend, after I move Reads[T] and Writes[T] converters to another object, it works.

Related

Scala: Play: Action classes — import behavior changed from Play 2.4 to Play 2.8

I am using Play 2.8.7, Scala 2.13.4.
import play.api.mvc._
import play.api.mvc.Results._
import play.mvc.Controller
import play.api.i18n.{I18nSupport, MessagesApi}
import javax.inject._
class Application #Inject() (
val messagesApi: MessagesApi
) extends Controller with I18nSupport {
def greeting = Action { implicit request =>
Ok("hello")
}
}
1. I want to import play.api.mvc.Results.Ok — why is it only imported when I do import play.api.mvc.Results._ but not when I only do import play.api.mvc._?
The latter used to work when I used Play 2.4.3 (Scala 2.11.11).
2. The compiler cannot resolve symbol "Action". Why is that...? I did import play.api.mvc._
UPDATE:
There was a suggestion to import play.mvc.BaseController.
It seems not to exist in Play 2.8.7.
"Controller" is for Java, so you should use "play.mvc.BaseController" in Scala.
Q1 & Q2 both would be resolved if you are using "play.mvc.BaseController". " import play.api.mvc.Results._" is also unnecessary.
import play.mvc.Controller and play.mvc.Result and extends your class to Controller.
Example:
import play.mvc.Controller;
import play.mvc.Result;
public class ClassName extends Controller {
//code
}

using package in Scala?

I have a scala project that uses akka. I want the execution context to be available throughout the project. So I've created a package object like this:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import com.datastax.driver.core.Cluster
package object connector {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
implicit val executionContext = executionContext
implicit val session = Cluster
.builder
.addContactPoints("localhost")
.withPort(9042)
.build()
.connect()
}
In the same package I have this file:
import akka.stream.alpakka.cassandra.scaladsl.CassandraSource
import akka.stream.scaladsl.Sink
import com.datastax.driver.core.{Row, Session, SimpleStatement}
import scala.collection.immutable
import scala.concurrent.Future
object CassandraService {
def selectFromCassandra()() = {
val statement = new SimpleStatement(s"SELECT * FROM animals.alpakka").setFetchSize(20)
val rows: Future[immutable.Seq[Row]] = CassandraSource(statement).runWith(Sink.seq)
rows.map{item =>
print(item)
}
}
}
However I am getting the compiler error that no execution context or session can be found. My understanding of the package keyword was that everything in that object will be available throughout the package. But that does not seem work. Grateful if this could be explained to me!
Your implementation must be something like this, and hope it helps.
package.scala
package com.app.akka
package object connector {
// Do some codes here..
}
CassandraService.scala
package com.app.akka
import com.app.akka.connector._
object CassandraService {
def selectFromCassandra() = {
// Do some codes here..
}
}
You have two issue with your current code.
When you compile your package object connector it is throwing below error
Error:(14, 35) recursive value executionContext needs type
implicit val executionContext = executionContext
Issue is with implicit val executionContext = executionContext line
Solution for this issue would be as below.
implicit val executionContext = ExecutionContext
When we compile CassandraService then it is throwing error as below
Error:(17, 13) Cannot find an implicit ExecutionContext. You might pass
an (implicit ec: ExecutionContext) parameter to your method
or import scala.concurrent.ExecutionContext.Implicits.global.
rows.map{item =>
Error clearly say that either we need to pass ExecutionContext as implicit parameter or import scala.concurrent.ExecutionContext.Implicits.global. In my system both issues are resolved and its compiled successfully. I have attached code for your reference.
package com.apache.scala
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import com.datastax.driver.core.Cluster
import scala.concurrent.ExecutionContext
package object connector {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
implicit val executionContext = ExecutionContext
implicit val session = Cluster
.builder
.addContactPoints("localhost")
.withPort(9042)
.build()
.connect()
}
package com.apache.scala.connector
import akka.stream.alpakka.cassandra.scaladsl.CassandraSource
import akka.stream.scaladsl.Sink
import com.datastax.driver.core.{Row, SimpleStatement}
import scala.collection.immutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object CassandraService {
def selectFromCassandra() = {
val statement = new SimpleStatement(s"SELECT * FROM animals.alpakka").setFetchSize(20)
val rows: Future[immutable.Seq[Row]] = CassandraSource(statement).runWith(Sink.seq)
rows.map{item =>
print(item)
}
}
}

how to store Select Statemnt data to var in scala play2.6 slick

I have written One SQL select query and i want to store the result returned from this query to some Variable how to do that
val count=(sql"""SELECT count(User_ID) from user_details_table where email=$email or Mobile_no=$Mobile_no""".as[(String)] )
val a1=Await.result(dbConfig.run(count), 1000 seconds)
Ok(Json.toJson(a1.toString()))
here i am not able to find out the id that is returning from this query
this is my complete code what i am trying to do
import javax.inject.Inject
import play.api.mvc.{AbstractController, ControllerComponents}
import javax.inject.Inject
import play.api.mvc.{AbstractController, ControllerComponents}
import scala.concurrent.Await
import javax.inject.Inject
import play.api.mvc._
import com.google.gson.{FieldNamingPolicy, Gson, GsonBuilder}
import play.api.libs.json.Json
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import javax.inject.Inject
import org.joda.time.format.DateTimeFormat
import play.api.libs.json.{JsPath, Writes}
import slick.jdbc.GetResult
import scala.concurrent.ExecutionContext.Implicits.global
//import play.api.mvc._
import org.joda.time.{DateTime, Period}
import play.api.libs.json.Json
import play.api.mvc._
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import com.google.gson.Gson
class adduserrs #Inject()(cc: ControllerComponents) extends AbstractController(cc)
{
def adduser(Name:String,Mobile_no:String,email:String,userpassword:String,usertype:String) = Action
{
import play.api.libs.json.{JsPath, JsValue, Json, Writes}
val gson: Gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create
val dbConfig = Database.forURL("jdbc:mysql://localhost:3306/equineapp?user=root&password=123456", driver = "com.mysql.jdbc.Driver")
var usertypeid=0;
if(usertype=="Owner")
{
usertypeid=1;
}
else if(usertype=="Practitioner")
{
usertypeid=2;
}
val count=(sql"""SELECT count(User_ID) from user_details_table where email=$email or Mobile_no=$Mobile_no""".as[(String)] )
val a1=Await.result(dbConfig.run(count), 1000 seconds)
Ok(Json.toJson(a1.toString()))
if (count==0) {
val setup1 = sql"call addusersreg ($Name,$Mobile_no,$email,$userpassword,$usertypeid);".as[(String, String, String, String, Int)]
val res = Await.result(dbConfig.run(setup1), 1000 seconds)
Ok(Json.toJson(1))
}
else {
Ok(Json.toJson(0))
}
}
from above code iam just trying to insert userdetails in database
if user exists in db then it will return response as 0 or else it will return response as 1
Ok, so here you are only counting, so perhaps you just need a variable of type Long:
SQL("select count(*) from User where tel = {telephoneNumber}")
.on('telephobeNumber -> numberThatYouPassedToTheMethod).executeQuery()
.as(SqlParser.scalar[Long].single)
You just totally changed the question, anyway, for the error you mentioned in the comment, the reason is that you have no connection as well as you did not define the database you want to use (default or otherwise). All the database calls are within the following block:
db.withConnection{
implicit connection =>
//SQL queries live here.
}
Moreover you need to db is injected if it is not the default database:
class myTestModel #Inject()(#NamedDatabase("nonDefaultDB") db: Database){???}
Follow MVC Architecture: For consistency with model-view-controller architecture, all your database calls should be within models classes. The controller method needs to call the models method for the result.

creating unmarshaller using circe

I am playing with Akka Http client side. I have created a simple request but how can I unmarshal the respose? in the server side it is easy to use circe to marshal the response, but I have difficulties in the client side
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.Materializer
import scala.concurrent.ExecutionContext
class QuestionsFetcher {
import de.heikoseeberger.akkahttpcirce.CirceSupport._
import io.circe.generic.auto._
val baseUrl = "https://somewhere.com"
def fetch(tag: String)(implicit ac: ActorSystem, materializer: Materializer) = {
implicit val ec: ExecutionContext = ac.dispatcher
val fromDate = DateTime.now.minus(1000 * 60 * 60 * 24)
val uri = Uri(baseUrl).withQuery(Query("order"->"desc"))
val request = HttpRequest(HttpMethods.GET, uri)
Http().singleRequest(request)
.map(r => Unmarshal(r.entity.withContentType(ContentTypes.`application/json`)).to[Items])
}
}
When running the code I am getting
ErrorFuture(io.circe.ParsingFailure: expected json value got (line 1, column 1))
the content was gziped - so after running the decoder flow
it was ok

Compiled Querys in Slick

I need to compile a query in Slick with Play and PostgreSQL
val bioMaterialTypes: TableQuery[Tables.BioMaterialType] = Tables.BioMaterialType
def getAllBmts() = for{ bmt <- bioMaterialTypes } yield bmt
val queryCompiled = Compiled(getAllBmts _)
but in Scala IDE I get this error in the Apply of Compiled
Multiple markers at this line
- Computation of type () => scala.slick.lifted.Query[models.Tables.BioMaterialType,models.Tables.BioMaterialTypeRow,Seq]
cannot be compiled (as type C)
- not enough arguments for method apply: (implicit compilable: scala.slick.lifted.Compilable[() =>
scala.slick.lifted.Query[models.Tables.BioMaterialType,models.Tables.BioMaterialTypeRow,Seq],C], implicit driver:
scala.slick.profile.BasicProfile)C in object Compiled. Unspecified value parameters compilable, driver.
This are my imports:
import scala.concurrent.Future
import scala.slick.jdbc.StaticQuery.staticQueryToInvoker
import scala.slick.lifted.Compiled
import scala.slick.driver.PostgresDriver
import javax.inject.Inject
import javax.inject.Singleton
import models.BioMaterialType
import models.Tables
import play.api.Application
import play.api.db.slick.Config.driver.simple.TableQuery
import play.api.db.slick.Config.driver.simple.columnExtensionMethods
import play.api.db.slick.Config.driver.simple.longColumnType
import play.api.db.slick.Config.driver.simple.queryToAppliedQueryInvoker
import play.api.db.slick.Config.driver.simple.queryToInsertInvoker
import play.api.db.slick.Config.driver.simple.stringColumnExtensionMethods
import play.api.db.slick.Config.driver.simple.stringColumnType
import play.api.db.slick.Config.driver.simple.valueToConstColumn
import play.api.db.slick.DB
import play.api.db.slick.DBAction
You can simply do
val queryCompiled = Compiled(bioMaterialTypes)