How to resolve java.nio.charset.UnmappableCharacterException in Scala 2.8.0? - exception

I'm using Scala 2.8.0 and trying to read pipe delimited file like in code snipped below:
object Main {
def main(args: Array[String]) :Unit = {
if (args.length > 0) {
val lines = scala.io.Source.fromPath("QUICK!LRU-2009-11-15.psv")
for (line <-lines)
print(line)
}
}
}
Here's the error:
Exception in thread "main" java.nio.charset.UnmappableCharacterException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:261)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:319)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.read(BufferedReader.java:157)
at scala.io.BufferedSource$$anonfun$1$$anonfun$apply$1.apply(BufferedSource.scala:29)
at scala.io.BufferedSource$$anonfun$1$$anonfun$apply$1.apply(BufferedSource.scala:29)
at scala.io.Codec.wrap(Codec.scala:65)
at scala.io.BufferedSource$$anonfun$1.apply(BufferedSource.scala:29)
at scala.io.BufferedSource$$anonfun$1.apply(BufferedSource.scala:29)
at scala.collection.Iterator$$anon$14.next(Iterator.scala:149)
at scala.collection.Iterator$$anon$2.next(Iterator.scala:745)
at scala.collection.Iterator$$anon$2.head(Iterator.scala:732)
at scala.collection.Iterator$$anon$24.hasNext(Iterator.scala:405)
at scala.collection.Iterator$$anon$20.hasNext(Iterator.scala:320)
at scala.io.Source.hasNext(Source.scala:209)
at scala.collection.Iterator$class.foreach(Iterator.scala:534)
at scala.io.Source.foreach(Source.scala:143)
...
at infillreports.Main$.main(Main.scala:8)
at infillreports.Main.main(Main.scala)
Java Result: 1

object Main {
def main(args: Array[String]) :Unit = {
if (args.length > 0) {
val lines = scala.io.Source.fromPath("QUICK!LRU-2009-11-15.psv")("UTF-8")
for (line <-lines)
print(line)
}
}
}

I was struggling with this same issue and this answer helped me. I wanted to extend on the comment of seh regarding the 'why this works'. The answer should lie on the method signature:
def fromFile(file: JFile)(implicit codec: Codec): BufferedSource
It takes an implict codec parameter. Yet, on the example, a string is provided, not a codec. A second translation is taking place behind the scenes:
The companion object of the class Codec defines an apply method from String:
def apply(encoding: String): Codec
so the compiler has done some work for us:
val lines = Source.fromFile(someFile)(Codec("UTF-8"))
Given that Codec is implicit, if you are calling this method several times, you can also create a Codec object in the scope of your call:
implicit val codec = Codec("UTF-8")
val lines = Source.fromFile(someFile)
val moreLines = Source.fromFile(someOtherFile)
I hope I got that right (I'm still a Scala n00b, getting my grips on it - feel free to correct where needed)

To add to Daniel C. Sobral's answer, you can also try something like this:
val products = Source.fromFile("products.txt")("UTF-8").getLines().toList;
for(p <- products){
println("product :" + p);
}

This maybe a more generic solution:
implicit val codec = Codec("UTF-8")
codec.onMalformedInput(CodingErrorAction.REPLACE)
codec.onUnmappableCharacter(CodingErrorAction.REPLACE)
with the two settings, you can avoid the malformed data in file.

Related

Scala cats - problem with encoding/decoding jsons

I have created a simple routes:
class MyRoutes[F[_] : Async](service: MyService[F]) extends Http4sDsl[F] {
def routes: HttpRoutes[F] = HttpRoutes.of[F] {
case req#PUT -> Root / "bets" =>
for {
bet <- req.as[Bet]
created <- service.put(bet)
response <- Created(created)
} yield response
}
and a jsons implicits for input and output:
object jsons {
implicit def circeDecoder[A[_] : Sync, B: Decoder]: EntityDecoder[A, B] = jsonOf[A, B]
implicit def circeEncoder[A[_] : Sync, B: Encoder]: EntityEncoder[A, B] = jsonEncoderOf[A, B]
}
But when I ran this program via Postman, I got an error:
The request body was invalid. with 422 error code. I think it is something wrong with json encoder and decoder, because my request was very simple and clear:
{
"stake": 434,
"name": "Something"
}
I tried to add an implicit decoder into routes:
implicit val betDecoder: EntityDecoder[F, Bet] = jsonOf[F, Bet]
but it also did not help. Could anyone help me with that and tell how to create good encoder and decoder for jsons? I use circe library for parsing.
Ok, stupid me, I solved the problem.
I had (probably) wrong definition of Bet. It was:
case class Bet(betId: BetId, stake: BigDecimal, name: String)
case class BetId(betId: String) extends AnyVal
So I should to give Id as a parameter. I changed the code to this one:
case class Bet(betId: Option[BetId], stake: BigDecimal, name: String)
case class BetId(betId: String) extends AnyVal
and after this one everything works correctly.
Another question is - is it good practise or could it be done in better way?

Implicit conversion of generic type T to JsValue in Play! Framework

I have a problem with declaring of generic method in Play 2.6 application that converts JSON to instance of one of the case class models.
All models declared with helper objects and formatters:
import play.api.libs.json.{Json, OFormat}
case class Shot(id: Long, likes_count: Long)
object Shot {
implicit val format: OFormat[Shot] = Json.format[Shot]
}
val s1: Shot = Json.toJson(f).as[Shot] // Works great
def testJsonGeneric[T](js: JsValue)(implicit ev: OFormat[T]): T = {
js.as[T](ev)
}
val s2: Shot = testJsonGeneric(Json.toJson(f)) // could not find implicit value for parameter ev: play.api.libs.json.OFormat[T]. Compilation failed
The last line of code throws
could not find implicit value for parameter ev: play.api.libs.json.OFormat[T]
But if I call my generic method like this (with explicit formatter) it works just fine:
val s2: Shot = testJsonGeneric(Json.toJson(f))(Shot.format)
However, it looks like if I expect my JSON to return a list of objects I have to define an extra formatter for List[Shot] to pass explicitly to the method when default Play's json.as[List[Shot]] could easily allow me to do this with a single existing formatter like the one that already defined in the helper object.
So, is it even possible to provide formatters implicitly for generic type T in my case?
Thank you
You can definitely do this, you just have to change the declaration a bit.
Move the case class and companion declaration outside the method, and then explicitly import Shot._ to bring the implicit in scope:
import play.api.libs.json.{JsValue, Json, OFormat}
object Foo {
case class Shot(id: Long, likes_count: Long)
object Shot {
implicit def format: OFormat[Shot] = Json.format[Shot]
}
def main(args: Array[String]): Unit = {
import Shot._
val f = Shot(1, 2)
def testJsonGeneric[T](js: JsValue)(implicit ev: OFormat[T]): T = {
js.as[T](ev)
}
val s2: Shot = testJsonGeneric(Json.toJson(f))
}
}

How to make Spray Json throw exception when it sees extra fields?

For example suppose I have
case class Test(a: String, b: String)
...
implicit val testFormat = jsonFormat2(Test.apply)
and a json with an extra c field:
val test = "{\"a\": \"A\", \"b\": \"B\", \"c\": \"C\"}"
then I want to find a way (config/param/whatever) to make the following line throw and exception:
test.parseJson.convertTo[Test]
It's very hard to work this out from reading the source code and github documentation.
I didn't see anything in the library that provides that functionality, so I created a wrapper that does a quick check on the number of fields present before delegating the read call to the supplied formatter.
case class StrictRootFormat[T](format: RootJsonFormat[T], size: Int) extends RootJsonFormat[T] {
def read(json: JsValue): T = {
if(json.asJsObject.fields.size > size) deserializationError("JSON has too many fields: \n " + json.toString())
else format.read(json)
}
def write(obj: T): JsValue = format.write(obj)
}
Usage:
implicit val testFormat = StrictRootFormat(jsonFormat2(Test.apply), 2)
You could enhance the read implementation so that you don't need to supply the "size" argument.

Scala Play - How to format Generics for JSON conversion

I am learning more and more about Scala and that nice playframework. But there are some things that bother me and that I can't get to work.
I like using Generics for some kind of collections, for example. But I need those to be stored in our database, in JSON. There is this cool auto conversion thing, but it does not work for generics, in no way I have tried :-/
Okay, to be concrete, code first:
case class InventorySlot(id: Long, item: Option[Item])
object InventorySlot {
implicit val fmt = Json.format[InventorySlot]
}
case class Inventory[T <: Item](slots: Vector[InventorySlot]) {
def length = slots.length
def items: Vector[T] = slots.map(slot => slot.item).flatten.asInstanceOf[Vector[T]]
def item(id: Long): Option[T] = {
slots.find(_.id == id) match {
case Some(slot: InventorySlot) =>
Some(slot.item.asInstanceOf[T])
case None =>
Logger.warn(s"slot with id $id not found")
None
}
}
}
object Inventory {
implicit val fmt = Json.format[Inventory]
}
Item is a basic abstract class of different items that can be put in that inventory. It doesn't matter. But sometimes I want to have an inventory, that just works for ItemType A, lets call it AItem.
So I want to create my inventory with something like this:
val myInventory = Inventory[AItem]("content of vector here") and when I call myInventory.item(2), then I want to get the item in slot 2, and it should be an object of type AItem, not just Item. (That's the reason why I am using generics here)
So the problem
The implicit format for Inventory does not work, obviously.
Item does, also with all special items, I can post the code for it below, and InventorySlot should work as well.
The error when compiling is:
Error:(34, 34) Play 2 Compiler:
C:\depot\mars\mainline\server\app\models\Test.scala:34: class Inventory takes type parameters
implicit val fmt = Json.format[Inventory]
^
I tried to write the read and write explicitly, like
implicit val fmt = (
(__ \ "slots").format[Vector[InventorySlot]]
)(Inventory.apply, unlift(Inventory.unapply))
wich is not even working in my IDE, and I can't find the problem.
I am confused. I don't know where my error lies, or if I am doing something wrong, or if I just miss something.
Any help will be appreciated.
I am so helpless, I even have considered doing a class for all possible inventory types, like
case class AItemInventory(protected var slots: Vector[InventorySlot]) extends Inventory[AItem](slots)
object AItemInventory {
implicit val fmt = Json.format[AItemInventory]
}
wich works. No problems, everything fine. So... I don't understand. Why is this working if it seems to be exactly the same, just hardcoded?
Appendix
The item formatter, wich works:
implicit val itemFormat = new Format[Item] {
override def reads(json: JsValue): JsResult[Item] = {
(json \ "itemType").as[ItemType] match {
case ItemType.AITEM => fmtAItem.reads(json)
}
}
override def writes(item: Item): JsValue = item match {
case subItem: AItem => fmtAItem.writes(subItem)
case _ => JsNumber(item.itemType.id)
}
}
object Inventory {
implicit def fmt[T <: Item](implicit fmt: Format[T]): Format[Inventory[T]] = new Format[Inventory[T]] {
def reads(json: JsValue): Inventory[T] = new Inventory[T] (
(json \ "blah").as[String]
)
def writes(i: Inventory[T]) = JsObject(Seq(
"blah" -> JsString(i.blah)
))
}
}
Source: documentation explains how to do it for reads and writes, and what I've done here is to combine these two for the format.

Handling Pk[Int] values in spray-json

[edit]
So, i got a quick and dirty solution, thanks to Edmondo1984, I don't know if it's the best solution. I don't handle null values with pattern matching at the write function. You can read more details about my problem after this editing. Here is my code now:
object DBNames extends DefaultJsonProtocol {
implicit val pkFormat: JsonFormat[Pk[Int]] = new JsonFormat[Pk[Int]] {
def write(obj: Pk[Int]): JsValue = JsNumber(obj.get)
def read(json: JsValue): Pk[Int] = json.asJsObject.getFields("id") match {
case Seq(JsNumber(id)) => new Pk[Int] { id.toInt }
case _ => throw new DeserializationException("Int expected")
}
}
implicit val nameFormat = jsonFormat2(Name)
jsonFormat2 will implicitly use pkFormat to parse Pk[Int] values.
In my controller class I have this:
def listNames() = Action {
val names = DBNames.findAll()
implicit val writer = DBNames.nameFormat
var json = names.toJson
Ok(json.toString()).as("application/json")
}
I had to get the nameFormat from my model and make it implicit, so bars.toJson could use it to parse the Seq[Name] names.
[/edit]
I'm trying to use Play! Framework with Scala, I'm new to Scala programming and Play Framework, and everything seems nice, but I'm working on this problem during several hours and didn't find a solution.
I have a Case Class:
case class Name (id: Pk[Int], name: String)
And an object to deal with MySql. I created a implicit val nameFormat = jsonFormat2(Name) to deal with JSON.
object DBNames extends DefaultJsonProtocol {
implicit val nameFormat = jsonFormat2(Name)
var parser =
{
get[Pk[Int]]("id") ~
get[String]("name") map {
case id ~ name => Name(id,name)
}
}
def findAll():Seq[Name] =
{
DB.withConnection {
implicit connection =>
SQL("select * from names").as(DBNames.parser *)
}
}
def create(name: Name){
DB.withConnection {
implicit connection =>
SQL("insert into names (name) values ({name})").on(
'name -> name.name
).executeUpdate()
}
}
}
But when I try to compile it, Play! gives me this result:
[error] D:\ProjetosJVM\TaskList\app\models\Names.scala:20: could not find implicit value for evidence parameter of type models.DBNames.JF[anorm.Pk[Int]]
It seems like he couldn't find a way to parse the id value, since it is a Pk[Int] value.
So, by reading this: https://github.com/spray/spray-json I didn't found a way to parse it without creating a complete object parser like they show in the documentation:
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ColorJsonFormat extends RootJsonFormat[Color] {
def write(c: Color) = JsObject(
"name" -> JsString(c.name),
"red" -> JsNumber(c.red),
"green" -> JsNumber(c.green),
"blue" -> JsNumber(c.blue)
)
def read(value: JsValue) = {
value.asJsObject.getFields("name", "red", "green", "blue") match {
case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue)) =>
new Color(name, red.toInt, green.toInt, blue.toInt)
case _ => throw new DeserializationException("Color expected")
}
}
}
}
I have a "big" (actually small) project where I want to make most of things work with Ajax, so I think this is not a good way to do it.
How can I deal with JSON objects in this project, where almost all case classes will have a "JSON parser", without creating large ammounts of code, like the snippet above? And also, how can I make it work with an Seq[Name]?
You don't need to write a complete parser. The compiler says:
[error] D:\ProjetosJVM\TaskList\app\models\Names.scala:20: could not find implicit
value for evidence parameter of type models.DBNames.JF[anorm.Pk[Int]]
The scala compiler is looking for an implicit parameter of type JF[anorm.Pk[Int]] and there is no such an implicit parameter in scope. What is JF[anorm.Pk[Int]]? Well, you need to know the library and I didn't, so I had browsed spray-json source and found out:
trait StandardFormats {
this: AdditionalFormats =>
private[json] type JF[T] = JsonFormat[T] // simple alias for reduced verbosity
so JF[T] is just an alias for JsonFormat[T]. It all make sense: PK[Int] is a class coming from Anorm and spray-json provides out-of-the-box json support for standard types, but does not even know Anorm exists So you have to code your support for Pk[Int] and make it implicit in scope.
You will have code like the following:
object DBNames extends DefaultJsonProtocol {
implicit val pkFormat : JsonFormat[Pk[Int]] = new JsonFormat[Pk[Int]] {
//implementation
}
// rest of your code
}
If you have just started with Scala, you would probably have to read more about implicits and their resolution. I am providing you with a minimal answer: once you have provided the right implementation, your code will compile. I suggest you to refer to the javadoc of anorm.Pk and of JsonFormat to understand how to implement it correctly for your type.
Pk looks like scala.Option and in StandardFormats source code inside spray-json you find the JsonFormat implementation for Option, from which you can copy