Why does pureconfig not find my implicit readers? - scala

I use double to encode boolean value in a configuration file. PureConfig does not find a way to cast it while reading the configuration.
Initial question (see below for edit).
Here is some code to reproduce the behavior.
import com.typesafe.config.ConfigFactory
import pureconfig.ConfigReader
import pureconfig.generic.auto._
object Main {
def main(args: Array[String]): Unit = {
println(pureconfig.loadConfig[BooleanTest](ConfigFactory.parseString("a = 1")))
}
}
case class BooleanTest(a: Boolean)
object ConfigImplicits {
implicit val myBooleanReader: ConfigReader[Boolean] = ConfigReader[Double].map { n => n > 0}
}
Here, I expect my code to print an instance of BooleanTest.
Instead, I got a ConvertFailure:
Left(ConfigReaderFailures(ConvertFailure(WrongType(NUMBER,Set(BOOLEAN)),None,a),List()))
One way to fix this, is to add import ConfigImplicits._ just before calling the loadConfig function.
However, as you can suppose, my code is actually part of a bigger project, and adding the import in the real project does not fix my error.
Do you have any hint on what can be wrong?
Kind,
Alexis.
Edit:
After comments from Thilo it appears logic to add the import statement.
Below is an updated version of the code which include the import statement but still produce the same error...
Change the main function to:
def main(args: Array[String]): Unit = {
println(ConfigUtils.loadConfig[BooleanTest]("a = 1"))
}
And declare a ConfigUtils object as follow:
object ConfigUtils {
def loadConfig[A : ConfigReader](str: String) : ConfigReader.Result[A] = {
import ConfigImplicits._
val config = ConfigFactory.parseString(str)
pureconfig.loadConfig[A](config)
}
}
Run the code and you get the same error as previously:
ConvertFailure(WrongType(NUMBER,Set(BOOLEAN))
Why does pureconfig not use my implicit myBooleanReader to parse this configuration?
Kind, Alexis.

Related

What is the correct way to register generic type to spray-json-support in akka-http Scala?

So, I have this class:
case class Something[T](data: Option[T] = None)
And i register it like the instruction said in https://github.com/spray/spray-json and in https://doc.akka.io/docs/akka-http/current/common/json-support.html. Like this:
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json.DefaultJsonProtocol
trait InternalJsonFormat extends SprayJsonSupport with DefaultJsonProtocol {
import spray.json._
implicit def somethingFormat[A :JsonFormat] = jsonFormat1(Something.apply[A])
}
And last i used complete from akka http directive. Like this:
import akka.http.scaladsl.server.Directives._
object ResponseIt extends InternalJsonFormat {
def apply[T](rawData: T) = {
val theResponse = Something(data = Some(rawData))
complete(theResponse)
}
}
And then i get an error in complete(theResponse). It said
Type mismatch, expected: ToResponseMarshallable, actual: Something[T]
===========================================================
I have try to edit the last code for debugging purpose, like this:
object ResponseIt extends InternalJsonFormat {
import spray.json._
def apply[T](rawData: T) = {
val theResponse = Something(data = Some(rawData))
val trying = theResponse.toJson
complete(theResponse)
}
}
and get new error in val trying = theResponse.toJson. like this:
No implicits found for parameter writer: JsonWriter[Something[T]]
So, i really confused what is wrong in my code?. Is there any correct way to use the spray json support in akka http?
Thanks in advance
You see, there is no evidence for existence of JsonFormat for your T here:
def apply[T](rawData: T) = {
// ^--- here
val theResponse = Something(data = Some(rawData))
val trying = theResponse.toJson
complete(theResponse)
}
One can rewrite this method to provide JsonFormat for generic T:
def apply[T](rawData: T)(implicit formatter: JsonFormat[T])

Scala : Putting similar things together

I am quite new to Scala Programming. I tried putting the similar things into a class and then need to invoke it from the driver.
Below is it what I finally ended up.
Is the way correct or should I follow a different approach ?
package com.cases
object Cases{
case class A(.....)
case class B(.....)
}
package com.utilities
object Utilities{
def utility1(...): ReturnType ={ }
def utility2(...): ReturnType ={ }
}
package com.driver
//Need to import these, in order to use the other two objects
import com.utilities._
import com.cases._
object Driver{
main(){
//call utility methods
val return = Utilities.utility1(....)
}
}

Scala compile time error while calling a method by passing List[Record]

I am doing some basic handson in scala.. i am getting compile-time error at the place of defining a method called processList.
The compile time error is
Multiple markers at this line:
- only classes can have declared but undefined
members
My code is as follows,
package pack1
import scala.io.Source
case class Record(id:Int, name:String, city:String)
object ReadingFile {
def main(args: Array[String]): Unit = {
val fileLoc:String = "/home/edureka/surender/inputfiles/records.txt"
val fileData:List[String] = Source.fromFile(fileLoc).getLines().toList
val fileList =fileData.map { eachLine => {
val Array(a:String,b:String,c:String) = eachLine.split(",")
Record(a.toInt,b,c)
} }
println(fileList)
processList(fileList)
}
def processList(myList:List[Record])
{
}
}
I dont know how to fix this, Can somebody help me on this?
Because of the new line after def processList(myList:List[Record]) Scala compiler thinks that the method implementation is not given and below block {} does not belong to the method. So compiler thinks its a abstract method.
Declare processList like this
def processList(myList:List[Record]) {
}
or
def processList(myList:List[Record]): Unit = {
}
Instead of this
def processList(myList:List[Record])
//remove this line to fix the error
{
}
The problem with this code is here,
def processList(myList:List[Record])
// <------ Notice this blank line
{
}
This leads the compiler to think that these are two different statements. And hence it thinks that you have left def processList(myList:List[Record]) without providing an implementation. And a class or case class and object can not have un-implemented members.
So... just fix that,
def processList(myList:List[Record]): Unit = {
}

Spray won't convert my case class to json and expect a spray.httpx.marshalling.ToResponseMarshallable

I'm trying to reprocude this or this, but I keep getting an error I am not able to fix...
First of all, here are my dependencies:
compile 'io.spray:spray-can_2.11:1.3.1'
compile 'io.spray:spray-routing_2.11:1.3.1',
compile 'io.spray:spray-json_2.11:1.2.6'
Now what I'm trying to do is:
class WHttpService extends Actor with HttpService with ActorLogging {
implicit def actorRefFactory = context
def receive = runRoute(route)
lazy val route = logRequest(showReq _) {
// Way too much imports but I tried all I could find
import spray.json._
import DefaultJsonProtocol._
import MasterJsonProtocol._
import spray.httpx.SprayJsonSupport._
path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
get {
complete {
Answer(1, "test")
}
}
}
}
private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}
With:
case object MasterJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport {
import spray.json._
case class Answer(code: Int, content: String)
implicit val anwserFormat: JsonFormat[Answer] = jsonFormat2(Answer)
}
Now I get this error:
Error:(42, 19) type mismatch;
found : MasterJsonProtocol.Answer
required: spray.httpx.marshalling.ToResponseMarshallable
Answer(1, "test")
^
I tried a lot of things but can't manage to make it works.
I tried with
Answer(1, "test").toJson
Answer(1, "test").toJson.asJsObject
Finally what I did was
complete {
Answer(1, "test").toJson.compactPrint
}
This works but it is sent to the client as Content-Type: text/plain when I need application/json.
Anyone see what the problem is here?
Edit: I added a sample project on github https://github.com/ydemartino/spray-test
Move your model outside of the json protocol and make it a regular object (not a case object)
case class Answer(code: Int, content: String)
object MasterJsonProtocol extends DefaultJsonProtocol {
implicit val anwserFormat = jsonFormat2(Answer)
}
Edit
Also clean up your imports:
class WHttpService extends Actor with HttpService with ActorLogging {
implicit def actorRefFactory = context
def receive = runRoute(route)
lazy val route = logRequest(showReq _) {
// Way too much imports but I tried all I could find
import MasterJsonProtocol._
import spray.httpx.SprayJsonSupport._
path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
get {
complete {
Answer(1, "test")
}
}
}
}
private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}
I created a pull request to fix your problem: https://github.com/ydemartino/spray-test/pull/1
The json protocol object has to be declared before it can be used implicitly. I'm not wholly sure why the compiler can't figure it out, but moving the object declaration to the top fixed it.
For your actual project make sure to declare packages in each file then use those packages to in the import statements.
In my case the name of the unresolvable implicit format instance conflicted with a local definition, so it got shadowed. The compiler was graciously silent about that. Only discovered that by accident after hours of head-banging.

Creating lazy sequence for file reading in scala

I want to create lazy sequence to read values from input stream in Scala.
import java.util._
object Main {
val input = new Scanner(System.in)
def main(args: Array[String]) {
val it = new MyIt().take(5)
}
class MyIt extends Iterator[Int] {
def hasNext = true
// def next = 29
def next = input.nextInt
}
}
When I changed next = 29 to next = input.nextInt, it would not compile any more complaining that MyIt has no member take. It looks I am completely misunderstanding something. Could you please give me hint (or perhaps link to good article on lazy sequences - there are a lot of results of google, but too much trash, seems - so I am getting lost)
import java.util._ overrides scala.collection.Iterator (which available by default via type alias in scala package object) with java.util.Iterator. Just change your import to import java.util.Scanner