Jackson Deserialize scala enum with integer value - scala

I am trying to deserialize a scala enumeration from integer value.
object TestEnum extends Enumeration {
type TestEnum = Value
val None = Value(0)
val One = Value(1)
val Two = Value(2)
val Four = Value(4) // scalastyle:ignore
#JsonCreator
def forValue(value: Int): TestEnum = {
TestEnum.Value(value)
}
}
class TestEnum extends TypeReference[TestEnum.type]
When I try to deserialize this field, it throws an error as - Cannot deserialize value of type com.example.TestEnum$from Integer value (tokenJsonToken.VALUE_NUMBER_INT)
I see the jackson doc suggests to use the JsonCreator for the same in java, however nothing mentioned for scala enum.
I am using the defaultScalaMapper without any customization here.

I was able to solve it with jsonCreator in the class using the enum. as follows -
class Example(testEnum: TestEnum) {
#JsonCreator
def this(testEnumNum: Int) = {
this(TestEnum.forValue(testEnumNum))
}
}
However I need to do this in every class, I was hoping if there can be a better solution for this.

Related

scala use template type to resolve sub class

I am fairly new to Scala and trying to do some code reuse. I have two enums AB and AC, both extend A which is a trait with some common methods.
object AB extends A[AB]{
val X = Value("x")
}
object AC extends A[AC]{
val Y = Value("y")
}
trait A[T] extends Enumeration{
def getProperty(prop: T.Value): String = {
//some code that uses prop.toString
}
I am trying to have a getProperty method that will restrict users to only Enums from the enumeration that it is being called upon.
if I call AB.getProperty() than i should be able to pass only X. if I call AC.getProperty than I should be able to pass only Y
If I have to redesign my classes that is fine. Please let me know how I can achieve this.
Thanks in advance
I am not sure what ConfigProperties is in your code, and why you need the type parameters, but the answer to your question is, declare the parameter type in geProperty as Value -> getProperty(prop: Value).
Value is a nested abstract class in Enumeration, so it will be expanded by the compiler respectively to AB.Value and XY.Value, depending on the instance. A simplified example which you can test in the REPL:
object AB extends A {
val A = Value('A')
val B = Value('B')
}
object XY extends A {
val X = Value('X')
val Y = Value('Y')
}
trait A extends Enumeration {
def getProperty(prop: Value): String = {
//some code that uses prop.toString
prop.toString()
}
}
AB.getProperty(AB.A) // OK
XY.getProperty(XY.Y) // Also OK
// AB.getProperty(XY.X) <- this won't compile
// Error:(21, 20) type mismatch;
// found : A$A238.this.XY.Value
// required: A$A238.this.AB.Value
// AB.getProperty(XY.X)
//

Jackson deserialize with Generics

I´m trying to deserialize a json into scala class, that contains a Collection of types Aclass,Bclass or Cclass
class Results[M](results:util.ArrayList[M]) {
def getResults:util.ArrayList[M]=results
def this() {
this(new util.ArrayList())
}
}
The Json looks like:
{ "results":[{"a":1},{"a":1}]}
or
{ "results":[{"b":1},{"b":1}]}
or
{ "results":[{"b":1},{"b":1}]}
Here my object mapper
val mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
And here how I deserialize a json of class type Aclass
val results = mapper.readValue(json, classOf[Results[Aclass]])
The problem is that results, return a ArrayList where every element instead to be an instance of Aclass, is a LinkedHashMap.
If I change the code instead to use generic I make it explicit in the type
class Results[Aclass](results:util.ArrayList[Aclass]) {
def getResults:util.ArrayList[Aclass]=results
def this() {
this(new util.ArrayList())
}
}
It works and return an class with result of array of Aclass elements.
What I´m doing wrong here?. I think it´s a bug in the library
Regards.
The reason is that java.lang.Class does not hold information about generic parameters. The value of classOf[Result[Aclass]] is java.lang.Class. It does not have information about the type parameter Aclass. It represents only the Results class.
The mapper does what you ask for: gives you Results of whatever and the best whatever for it is a map.
To solve it, use readValue method that takes JavaType instead. JavaType can be created using TypeFactory:
val results:Results[Aclass] = mapper.readValue(json, mapper.getTypeFactory()
.constructParametricType(classOf[Results[_]], classOf[Aclass]))

How to add reusable field to Scala Enumeration?

I would like to extend Scala's implementation of Enumeration with a custom field, say label. That new field should be accessible via the values of that enumeration. Furthermore, that custom field should be part of various implementations of Enumeration.
I am aware of the following questions at Stackoverflow:
How to add a method to Enumeration in Scala?
How do I create an enum in scala that has an extra field
Overriding Scala Enumeration Value
Scala doesn't have enums - what to use instead of an enum
However, none of them solves my issues:
The first issue is that I am able to add a custom field. However, I cannot access that additional field via the Values returned by Enumeration.values. The following code works and prints 2nd enumeration value:
object MyEnum extends Enumeration {
type MyEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
val VALUE_THREE = MyVal(Some("3rd value"))
case class MyVal(label: Option[String] = None) extends Val(nextId)
}
import MyEnum._
println(VALUE_TWO.label.get)
Note that I access the label via one of the values. The following code does not work:
for (value <- MyEnum.values) println(value.label)
The error message is as follows: error: value label is not a member of MyEnum.Value
Obviously, instead of MyEnum.MyVal, MyEnum.Val is used. The latter does not define label, while my custom value would provide field label.
The second issue is that it seems to be possible to introduce a custom Value and Val, respectively, in the context of an Enumeration only. Thus, as far as I know, it is not possible to use such a field across different enums. At least, the following code does not compile:
case class MyVal(label: Option[String] = None) extends Enumeration.Val(nextId)
object MyEnum extends Enumeration {
type MyEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
}
object MySecondEnum extends Enumeration {
type MySecondEnum = MyVal
val VALUE_ONE = MyVal()
val VALUE_TWO = MyVal(Some("2nd enumeration value"))
}
Due to the fact that class Val is protected, case class MyVal cannot access Val -- MyVal is not defined in the context of an enumeration.
Any idea how to solve the above issues?
The first issue is addressed by a recent question, my answer to which got no love.
For that use case, I would write a custom widgets method with the useful type, but my linked answer, which just introduces an implicit conversion, seems pretty handy. I don't know why it's not the canonical solution.
For the second issue, your derived MyVal should just implement a trait.
Sample:
scala> trait Labelled { def label: Option[String] }
defined trait Labelled
scala> object A extends Enumeration { case class AA(label: Option[String]) extends Val with Labelled ; val X = AA(Some("one")) }
defined object A
scala> object B extends Enumeration { case class BB(label: Option[String]) extends Val with Labelled ; val Y = BB(None) }
defined object B
scala> val labels = List(A.X, B.Y)
labels: List[Enumeration#Val with Product with Labelled] = List(X, Y)
scala> labels map (_.label)
res0: List[Option[String]] = List(Some(one), None)

How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration

I am upgrading existing code from Rogue 1.1.8 to 2.0.0 and lift-mongodb-record from 2.4-M5 to 2.5.
I'm having difficulty writing MongoCaseClassField that contains a scala enum, that I really could use some help with.
For example,
object MyEnum extends Enumeration {
type MyEnum = Value
val A = Value(0)
val B = Value(1)
}
case class MyCaseClass(name: String, value: MyEnum.MyEnum)
class MyMongo extends MongoRecord[MyMongo] with StringPk[MyMongo] {
def meta = MyMongo
class MongoCaseClassFieldWithMyEnum[OwnerType <: net.liftweb.record.Record[OwnerType], CaseType](rec : OwnerType)(implicit mf : Manifest[CaseType]) extends MongoCaseClassField[OwnerType, CaseType](rec)(mf) {
override def formats = super.formats + new EnumSerializer(MyEnum)
}
object myCaseClass extends MongoCaseClassFieldWithMyEnum[MyMongo, MyCaseClass](this)
/// ...
}
When we try to write to this field, we get the following error:
could not find implicit value for evidence parameter of type
com.foursquare.rogue.BSONType[MyCaseClass]
.and(_.myCaseClass setTo myCaseClass)
We used to have this working in Rogue 1.1.8, by using our own version of the MongoCaseClassField, which made the #formats method overridable. But that feature was included into lift-mongodb-record in 2.5-RC6, so we thought this should just work now?
Answer coming from : http://grokbase.com/t/gg/rogue-users/1367nscf80/how-to-update-a-record-with-mongocaseclassfield-when-case-class-contains-a-scala-enumeration#20130612woc3x7utvaoacu7tv7lzn4sr2q
But more convenient directly here on StackOverFlow:
Sorry, I should have chimed in here sooner.
One of the long-standing problems with Rogue was that it was too easy to
accidentally make a field that was not serializable as BSON, and have it
fail at runtime (when you try to add that value to a DBObject) rather than
at compile time.
I introduced the BSONType type class to try to address this. The upside is
it catches BSON errors at compile time. The downside is you need to make a
choice when it comes to case classes.
If you want to do this the "correct" way, define your case class plus a
BSONType "witness" for that case class. To define a BSONType witness, you
need to provide serialization from that type to a BSON type. Example:
case class TestCC(v: Int)
implicit object TestCCIsBSONType extends BSONType[TestCC] {
override def asBSONObject(v: TestCC): AnyRef = {
// Create a BSON object
val ret = new BasicBSONObject
// Serialize all the fields of the case class
ret.put("v", v.v)
ret
}
}
That said, this can be quite burdensome if you're doing it for each case
class. Your second option is to define a generic witness that works for any
case class, if you have a generic serialization scheme:
implicit def CaseClassesAreBSONTypes[CC <: CaseClass]: BSONType[CC] =
new BSONType[CC] {
override def asBSONObject(v: CC): AnyRef = {
// your generic serialization code here, maybe involving formats
}
}
Hope this helps,

How do I create a class hierarchy of typed factory method constructors and access them from Scala using abstract types?

(Essentially I need some kind of a synthesis of these two questions (1, 2), but I'm not smart enough to combine them myself.)
I have a set of JAXB representations in Scala like this:
abstract class Representation {
def marshalToXml(): String = {
val context = JAXBContext.newInstance(this.getClass())
val writer = new StringWriter
context.createMarshaller.marshal(this, writer)
writer.toString()
}
}
class Order extends Representation {
#BeanProperty
var name: String = _
...
}
class Invoice extends Representation { ... }
The problem I have is with my unmarshalling "constructor" methods:
def unmarshalFromJson(marshalledData: String): {{My Representation Subclass}} = {
val mapper = new ObjectMapper()
mapper.getDeserializationConfig().withAnnotationIntrospector(new JaxbAnnotationIntrospector())
mapper.readValue(marshalledData, this.getClass())
}
def unmarshalFromXml(marshalledData: String): {{My Representation Subclass}} = {
val context = JAXBContext.newInstance(this.getClass())
val representation = context.createUnmarshaller().unmarshal(
new StringReader(marshalledData)
).asInstanceOf[{{Type of My Representation Subclass}}]
representation // Return the representation
}
Specifically, I can't figure out how to attach these unmarshalling methods in a typesafe and DRY way to each of my classes, and then to call them from Scala (and hopefully sometimes by using only abstract type information). In other words, I would like to do this:
val newOrder = Order.unmarshalFromJson(someJson)
And more ambitiously:
class Resource[R <: Representation] {
getRepresentation(marshalledData: String): R =
{{R's Singleton}}.unmarshalFromXml(marshalledData)
}
In terms of my particular stumbling blocks:
I can't figure out whether I should define my unmarshalFrom*() constructors once in the Representation class, or in a singleton Representation object - if the latter, I don't see how I can automatically inherit that down through the class hierarchy of Order, Invoice etc.
I can't get this.type (as per this answer) to work as a way of self-typing unmarshalFromJson() - I get a compile error type mismatch; found: ?0 where type ?0 required: Representation.this.type on the readValue() call
I can't figure out how to use the implicit Default[A] pattern (as per this answer) to work down my Representation class hierarchy to call the singleton unmarshalling constructors using type information only
I know this is a bit of a mammoth question touching on various different (but related) issues - any help gratefully received!
Alex
The key is to not try and attach the method to the class but rather pass it in as a parameter. To indicate the type you are expecting and let the type system handle passing it in. I tried to make the unmarshal invocation something that reads a little DSL like.
val order = UnMarshalXml( xml ).toRepresentation[Order]
The following is a fully testable code snippet
abstract class Representation {
def marshalToXml(): String = {
val context = JAXBContext.newInstance(this.getClass)
val writer = new StringWriter
context.createMarshaller.marshal(this, writer)
writer.toString
}
}
#XmlRootElement
class Order extends Representation {
#BeanProperty
var name: String = _
}
case class UnMarshalXml( xml: String ) {
def toRepresentation[T <: Representation](implicit m:Manifest[T]): T = {
JAXBContext.newInstance(m.erasure).createUnmarshaller().unmarshal(
new StringReader(xml)
).asInstanceOf[T]
}
}
object test {
def main( args: Array[String] ) {
val order = new Order
order.name = "my order"
val xml = order.marshalToXml()
println("marshalled: " + xml )
val received = UnMarshalXml( xml ).toRepresentation[Order]
println("received order named: " + received.getName )
}
}
You should see the following output if you run test.main
marshalled: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><order><name>my order</name></order>
received name: my order
Here's the updated version of Neil's code which I used to support the second use case as well as the first:
case class UnmarshalXml(xml: String) {
def toRepresentation[T <: Representation](implicit m: Manifest[T]): T =
toRepresentation[T](m.erasure.asInstanceOf[Class[T]])
def toRepresentation[T <: Representation](typeT: Class[T]): T =
JAXBContext.newInstance(typeT).createUnmarshaller().unmarshal(
new StringReader(xml)
).asInstanceOf[T]
}
This supports simple examples like so:
val order = UnmarshalXml(xml).toRepresentation[Order]
But also for abstract type based usage, you can use like this:
val order = UnmarshalXml(xml).toRepresentation[T](typeOfT)
(Where you have grabbed and stored typeOfT using another implicit Manifest at the point of declaring T.)