How to Conditionally Produce JSON Using JSON4S - json

I am using JSON4S to produce some JSON.
If a condition is met, I would like to produce the following:
{"fld1":"always", "fld2":"sometimes"}
If the condition is not met, I would like to produce:
{"fld1":"always"}
What I have tried so far is:
val fld1 = "fld1" -> "always"
val json = if(condition) ("fld2" -> "sometimes") ~ fld1 else fld1
compact(render(json))
However, this gives me a type mismatch in the render "Found: Product with Serializable. Required: org.json4s.package.JValue".
The interesting this is that render(("fld2" -> "sometimes") ~ fld1) works, and so does render(fld1). The problem seems to be with the type inferred for json.
How could I fix this?

While both of the current answers give suitable workarounds, neither explains what's going on here. The problem is that if we have two types, like this:
trait Foo
trait Bar
And an implicit conversion (or view) from one to the other:
implicit def foo2bar(foo: Foo): Bar = new Bar {}
A conditional with a Foo for its then clause and a Bar for its else clause will still be typed as the least upper bound of Foo and Bar (in this case Object, in your case Product with Serializable).
This is because the type inference system isn't going to step in and say, well, we could view that Foo as a Bar, so I'll just type the whole thing as a Bar.
This makes sense if you think about it—for example, if it were willing to handle conditionals like that, what would it do if we had implicit conversions both ways?
In your case, the then clause is typed as a JObject, and the else clause is a (String, String). We have a view from the latter to the former, but it won't be used here unless you indicate that you want the whole thing to end up as a JObject, either by explicitly declaring the type, or by using the expression in a context where it has to be a JObject.
Given all of that, the simplest workaround may just be to make sure that both clauses are appropriately typed from the beginning, by providing a type annotation like this for fld1:
val fld1: JObject = "fld1" -> "always"
Now your conditional will be appropriately typed as it is, without the type annotation.

Not the nicest way I can think of, but declaring the type yourself should work:
val json: JObject =
if(condition) ("fld2" -> "sometimes") ~ fld1 else fld1
compact(render(json))
Also, note that you can get type inference to help itself out: If you can render in one go:
compact(render(
if(condition) fld1 ~ ("fld2" -> "sometimes") else fld1
))

Another approach is to box conditional values to Options.
val json = fld1 ~ ("fld2" -> (if (condition) Some("sometimes") else None))
compact(render(json))

Related

Is there a elegant way to handle Either Monad in Scala?

I am starting up on Scala, doing a project with circe to handle JSON.
I am coming accross a lot of Either returns from functions, and I don't seem to find a elegant way to handle all of them.
For instance, for a single either, I do as in this snippet:
if (responseJson.isRight) {
//do something
} else {
//do something else
}
But what should I do when I have a lot of them in sequence, such as this example in which I just go straight for the right side and I feel I should be doing some extra validation:
ClassA(
someValue,
someValue,
someJson.hcursor.get[Double]("jsonKey1").right.get,
someJson.hcursor.get[Double]("jsonKey2").right.get,
someJson.hcursor.get[Double]("jsonKey3").right.get
)
How should/can I handle multiple Either objects (without ending up with a bunch of if-elses, or similar) when I want to get their contents if they are a Right, but not I am not sure they are always a Right ?
Lets say you have a case class,
case class Demo(i: Int, s: String)
and two eithers,
val intEither: Either[Throwable, Int] = ???
val stringEither: Either[Throwable, Int] = ???
So... lets start with the most basic and obvious one,
val demoEither: Either[Throwable, Demo] =
intEither.flatMap(i =>
stringEither.map(s => Demo(i, s))
)
Another way is to do the same as above is to use for-comprehensions,
val demoEither: Either[Throwable, Demo] =
for {
i <- intEither
s <- stringEither
} yield Demo(i, s)
But, monads are sequential, which means that if the first Either is a Left then you will not even look at the second Either and just get a Left. This is mostly undesirable for validations because you don't want to loose the validation information of all components, so what you actually want is an Applicative.
And Either is not an Applicative, you will have to use cats or scalaz or implement your own applicative for this.
cats provides the Validated applicative for this express purpose which lets you validate and keep all error information of the validated components.
import cats.data._
import cats.implicits._
val intValidated: ValidatedNec[Throwable, Int] =
intEither.toValidatedNec
val stringValidated: ValidatedNec[Throwable, String] =
stringEither.toValidatedNec
val demoValidated: ValidatedNec[Throwable, Demo] =
(intValidated, stringValidated).mapN(Demo)
val demoEither: Either[List[Throwable], Demo] =
demoValidated.leftMap(errorNec => errorNec.toList)
Or, if you are doing this just once and don't want to depend on cats, you can just use pattern-matching which is very versatile
val demoEither: Either[List[Throwable], Demo] =
(intEither, stringEither) match {
case (Right(i), Right(s)) => Right(Demo(i, s))
case (Left(ti), Left(ts)) => Left(List(ti, ts))
case (Left(ti), _) => Left(List(ti))
case (_, Left(ts)) => Left(List(ts))
}
How should/can I handle multiple Either objects (without ending up with a bunch of if-elses, or similar) when I want to get their contents if they are a Right, but not I am not sure they are always a Right?
So you have some Either instances, all with the same type signature.
val ea :Either[Throwable,String] = Right("good")
val eb :Either[Throwable,String] = Left(new Error("bad"))
val ec :Either[Throwable,String] = Right("enough")
And you want all the Right values, ignoring any Left values.
List(ea, eb, ec).collect{case Right(x) => x}
//res0: List[String] = List(good, enough)
You don't know which Either contains which String but I think that's what you asked for.

How to convert jsonAST.Jint to int

I am attempting to learn Scala, and I'm trying to parse a JSON file. I have two lines of code:
var jVal:JValue = parse(json);
val totalCount:Int = (jVal \\ "totalCount").asInstanceOf[Int];
However, (jVal \\ "totalCount") returns a JInt instead of an int. If I print it as a string, it looks like "JInt(38)".
How on earth do I convert this to a regular int? My current code throws an exception saying that
net.liftweb.json.JsonAST$JInt cannot be cast to java.lang.Integer
I've scoured the internet, but I can't find any answers. I would really prefer not to manually parse and remove the "JInt()" part of the string just to get it as an integer.
Surely I am missing a simple way to do this?
Since JInt is a case class, a convenient way to extract the value is using an extractor expression, either in a match:
myJValue match {
case JInt(x) => /* do something with x */
case JString(s) => /* do something with s */
/* etc. */
}
or just an assignment statement, when you know what type to expect:
val JInt(totalCount) = (jVal \\ "totalCount")
This will define totalCount to be the value of "totalCount" in your JSON. Note that it will be of type BigInt. If you want to, you can convert your BigInt to an Int with the toInt method. But if your number is too big for an Int, this method will give you a different number instead of an error. So if huge numbers are at all a possibility, you'll want to check first with isValidInt.
You can also get the value using the num field or values method, but in your code that's harder to work with. To use num, you'd have to do a cast of your JValue to JInt. And if you don't cast to JInt, you won't know the type of the result of values.

How to read value of property depending on an argument

How can I get the value of a property given a string argument.
I have a Object CsvProvider.Row which has attributes a,b,c.
I want to get the attribute value depending on property given as a string argument.
I tried something like this:
let getValue (tuple, name: string) =
snd tuple |> Seq.averageBy (fun (y: CsvProvider<"s.csv">.Row) -> y.```name```)
but it gives me the following error:
Unexpected reserved keyword in lambda expression. Expected incomplete
structured construct at or before this point or other token.
Simple invocation of function should look like this:
getValue(tuple, "a")
and it should be equivalent to the following function:
let getValue (tuple) =
snd tuple |> Seq.averageBy (fun (y: CsvProvider<"s.csv">.Row) -> y.a)
Is something like this is even possible?
Thanks for any help!
The CSV type provider is great if you are accessing data by column names statically, because you get nice auto-completion with type inference and checking.
However, for a dynamic access, it might be easier to use the underlying CsvFile (also a part of F# Data) directly, rather than using the type provider:
// Read the given file
let file = CsvFile.Load("c:/test.csv")
// Look at the parsed headers and find the index of column "A"
let aIdx = file.Headers.Value |> Seq.findIndex (fun k -> k = "A")
// Iterate over rows and print A values
for r in file.Rows do
printfn "%A" (r.Item(aIdx))
The only unfortunate thing is that the items are accessed by index, so you need to build some lookup table if you want to easily access them by their name.

pattern match any into a list

I get the following as a result from using the scala json parse.
import scala.util.parsing.json.JSON._
val j: String = """["this",["a","b",["c","d"]]]"""
val parse_test=parseFull(j)
now from this I get a result of Option[Any]
I can use get to obtain the results (in this case I am not concerned about invalid json format, so this should be safe, right?)
parse_test.get
res26: Any = List(this, List(a, b, List(c, d)))
Now, how should I go about going from this Any to the List that I had expected? I assume I should use pattern matching, but I can't figure it out. Any help would be much appreciated
Here is my solution:
scala> val Some(xs # List(_*)) = parse_test
xs: List[Any] = List(this, List(a, b, List(c, d)))
What you could do is a fold with a pattern match and a cast:
test_result.fold[List[String]](Nil){
case _ :: list :: _ => list.asInstanceOf[List[String]]
case _ => Nil
}
Assuming you're trying to throw out of the first element and that the 2nd element is the list you wanted.
Edit:
Be aware that if the 2nd element isn't a list this cast would cause an exception. It's really horrible dealing with a List[Any] and trying to decode what's in there...

Scala by Example - type bounds parametrized function compiler complains

I would like to implement a type-parametrized function as per excersize on page 72 of the book (implement forall using filter):
def forallA[B <: A](xs:List[A])(f:A => B) : List[B] = {
xs.filter(x => true) match {
case Nil => Nil
case y :: ys => f(y) :: forallA(ys)(f)
}
}
However, the compiler(2.9.1) complains about the type A being undefined. Clearly that should not be the case, since multiple examples in the same book use this syntax. The issue can be cured by changnig the function type parameter to [A, B <: A]. Am I doing something wrong, or is it again, a terrific change in Scala's syntax specification? If so, I am, frankfully, tired of bombing SO with such stupid questions on every second excersize. Could anyone recommend a book that clearly reflects the current order of things?
You already gave the answer: If you want to bound the type parameter B with another type parameter A, you have to add this to the list of type parameters:
def forall[A, B <: A](...)(...) = ...
Else you are referring to something undefined. Maybe it helps if you think of type parameters like usual (method) parameters. How should something like the following compile:
def add(x: Int) = x + y
Here the parameter y is undefined, just like in your case A was undefined.