Permalink
Browse files

Merge branch 'master' of github.com:lift/framework

  • Loading branch information...
2 parents 0b8ce63 + 7c91856 commit a8ec5d8556a99ebb34da8d442900bd61922384f0 @andreak andreak committed Nov 2, 2011
View
120 core/json-ext/src/main/scala/net/liftweb/json/ext/JodaTimeSerializer.scala
@@ -27,52 +27,60 @@ object JodaTimeSerializers {
LocalTimeSerializer(), PeriodSerializer())
}
-object PeriodSerializer {
- def apply() = new SimpleTypeSerializer(new JStringType[Period]() {
- def targetClass = classOf[Period]
- def unwrap(json: JString)(implicit format: Formats) = new Period(json.s)
- def wrap(a: Period)(implicit format: Formats) = JString(a.toString)
- })
-}
-
-object DurationSerializer {
- def apply() = new SimpleTypeSerializer(new JIntType[Duration]() {
- def targetClass = classOf[Duration]
- def unwrap(json: JInt)(implicit format: Formats) = new Duration(json.num.longValue)
- def wrap(a: Duration)(implicit format: Formats) = JInt(a.getMillis)
- })
-}
-
-object InstantSerializer {
- def apply() = new SimpleTypeSerializer(new JIntType[Instant]() {
- def targetClass = classOf[Instant]
- def unwrap(json: JInt)(implicit format: Formats) = new Instant(json.num.longValue)
- def wrap(a: Instant)(implicit format: Formats) = JInt(a.getMillis)
- })
-}
-
-object DateTimeSerializer {
- def apply() = new SimpleTypeSerializer(new JStringType[DateTime]() {
- def targetClass = classOf[DateTime]
- def unwrap(json: JString)(implicit format: Formats) = new DateTime(parse(json))
- def wrap(a: DateTime)(implicit format: Formats) = JString(format.dateFormat.format(a.toDate))
- })
+case class PeriodSerializer extends CustomSerializer[Period](format => (
+ {
+ case JString(p) => new Period(p)
+ case JNull => null
+ },
+ {
+ case p: Period => JString(p.toString)
+ }
+))
+
+case class DurationSerializer extends CustomSerializer[Duration](format => (
+ {
+ case JInt(d) => new Duration(d.longValue)
+ case JNull => null
+ },
+ {
+ case d: Duration => JInt(d.getMillis)
+ }
+))
+
+case class InstantSerializer extends CustomSerializer[Instant](format => (
+ {
+ case JInt(i) => new Instant(i.longValue)
+ case JNull => null
+ },
+ {
+ case i: Instant => JInt(i.getMillis)
+ }
+))
- private[ext] def parse(json: JString)(implicit format: Formats) =
- format.dateFormat.parse(json.s).map(_.getTime).getOrElse {
- throw new MappingException("Invalid date format " + json.s)
- }
+object DateParser {
+ def parse(s: String, format: Formats) =
+ format.dateFormat.parse(s).map(_.getTime).getOrElse(throw new MappingException("Invalid date format " + s))
}
-object DateMidnightSerializer {
- def apply() = new SimpleTypeSerializer(new JStringType[DateMidnight]() {
- def targetClass = classOf[DateMidnight]
- def unwrap(json: JString)(implicit format: Formats) =
- new DateMidnight(DateTimeSerializer.parse(json))
- def wrap(a: DateMidnight)(implicit format: Formats) =
- JString(format.dateFormat.format(a.toDate))
- })
-}
+case class DateTimeSerializer extends CustomSerializer[DateTime](format => (
+ {
+ case JString(s) => new DateTime(DateParser.parse(s, format))
+ case JNull => null
+ },
+ {
+ case d: DateTime => JString(format.dateFormat.format(d.toDate))
+ }
+))
+
+case class DateMidnightSerializer extends CustomSerializer[DateMidnight](format => (
+ {
+ case JString(s) => new DateMidnight(DateParser.parse(s, format))
+ case JNull => null
+ },
+ {
+ case d: DateMidnight => JString(format.dateFormat.format(d.toDate))
+ }
+))
private[ext] case class _Interval(start: Long, end: Long)
object IntervalSerializer {
@@ -101,7 +109,6 @@ object LocalTimeSerializer {
})
}
-// FIXME consider moving these utilities to lift-json in some form
private[ext] trait ClassType[A, B] {
def unwrap(b: B)(implicit format: Formats): A
def wrap(a: A)(implicit format: Formats): B
@@ -122,28 +129,3 @@ case class ClassSerializer[A : Manifest, B : Manifest](t: ClassType[A, B]) exten
case a: A if a.asInstanceOf[AnyRef].getClass == Class => Extraction.decompose(t.wrap(a))
}
}
-
-private[ext] trait SimpleType[A, JS <: JValue] {
- def targetClass: Class[A]
- def unwrap(json: JS)(implicit format: Formats): A
- def wrap(a: A)(implicit format: Formats): JS
-}
-
-private[ext] trait JIntType[A] extends SimpleType[A, JInt]
-private[ext] trait JStringType[A] extends SimpleType[A, JString]
-
-private[ext] class SimpleTypeSerializer[A, JS <: JValue](t: SimpleType[A, JS]) extends Serializer[A] {
- private val Class = t.targetClass
-
- def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), A] = {
- case (TypeInfo(Class, _), json) => json match {
- case JNull => null.asInstanceOf[A]
- case json: JS => t.unwrap(json)
- case value => throw new MappingException("Can't convert " + value + " to " + Class)
- }
- }
-
- def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
- case d: A if d.asInstanceOf[AnyRef].getClass == t.targetClass => t.wrap(d)
- }
-}
View
26 core/json/README.md
@@ -573,28 +573,22 @@ by providing following serializer.
val endTime = end
}
- scala> class IntervalSerializer extends Serializer[Interval] {
- private val IntervalClass = classOf[Interval]
-
- def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Interval] = {
- case (TypeInfo(IntervalClass, _), json) => json match {
- case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
- new Interval(s.longValue, e.longValue)
- case x => throw new MappingException("Can't convert " + x + " to Interval")
- }
- }
-
- def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
+ scala> class IntervalSerializer extends CustomSerializer[Interval](format => (
+ {
+ case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
+ new Interval(s.longValue, e.longValue)
+ },
+ {
case x: Interval =>
JObject(JField("start", JInt(BigInt(x.startTime))) ::
- JField("end", JInt(BigInt(x.endTime))) :: Nil)
+ JField("end", JInt(BigInt(x.endTime))) :: Nil)
}
- }
+ ))
scala> implicit val formats = Serialization.formats(NoTypeHints) + new IntervalSerializer
-Function 'serialize' creates a JSON object to hold serialized data. Function 'deserialize' knows how
-to construct serialized object by pattern matching against type info and data.
+Custom serializer is created by providing two partial functions. The first evaluates to a value
+if it can unpack the data from JSON. The second creates the desired JSON if the type matches.
Extensions
----------
View
14 core/json/src/main/scala/net/liftweb/json/Formats.scala
@@ -268,3 +268,17 @@ private[json] class ThreadLocal[A](init: => A) extends java.lang.ThreadLocal[A]
override def initialValue = init
def apply = get
}
+
+class CustomSerializer[A: Manifest](
+ ser: Formats => (PartialFunction[JValue, A], PartialFunction[Any, JValue])) extends Serializer[A] {
+
+ val Class = implicitly[Manifest[A]].erasure
+
+ def deserialize(implicit format: Formats) = {
+ case (TypeInfo(Class, _), json) =>
+ if (ser(format)._1.isDefinedAt(json)) ser(format)._1(json)
+ else throw new MappingException("Can't convert " + json + " to " + Class)
+ }
+
+ def serialize(implicit format: Formats) = ser(format)._2
+}
View
66 core/json/src/test/scala/net/liftweb/json/SerializationExamples.scala
@@ -232,54 +232,36 @@ object CustomSerializerExamples extends Specification {
import JsonAST._
import java.util.regex.Pattern
- class IntervalSerializer extends Serializer[Interval] {
- private val IntervalClass = classOf[Interval]
-
- def deserialize(implicit format: Formats) = {
- case (TypeInfo(IntervalClass, _), json) => json match {
- case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
- new Interval(s.longValue, e.longValue)
- case x => throw new MappingException("Can't convert " + x + " to Interval")
- }
- }
-
- def serialize(implicit format: Formats) = {
+ class IntervalSerializer extends CustomSerializer[Interval](format => (
+ {
+ case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
+ new Interval(s.longValue, e.longValue)
+ },
+ {
case x: Interval =>
JObject(JField("start", JInt(BigInt(x.startTime))) ::
- JField("end", JInt(BigInt(x.endTime))) :: Nil)
+ JField("end", JInt(BigInt(x.endTime))) :: Nil)
}
- }
-
- class PatternSerializer extends Serializer[Pattern] {
- private val PatternClass = classOf[Pattern]
-
- def deserialize(implicit format: Formats) = {
- case (TypeInfo(PatternClass, _), json) => json match {
- case JObject(JField("$pattern", JString(s)) :: Nil) => Pattern.compile(s)
- case x => throw new MappingException("Can't convert " + x + " to Pattern")
- }
+ ))
+
+ class PatternSerializer extends CustomSerializer[Pattern](format => (
+ {
+ case JObject(JField("$pattern", JString(s)) :: Nil) => Pattern.compile(s)
+ },
+ {
+ case x: Pattern => JObject(JField("$pattern", JString(x.pattern)) :: Nil)
}
-
- def serialize(implicit format: Formats) = {
- case x: Pattern => JObject(JField("$pattern", JString(x.pattern)) :: Nil)
- }
- }
-
- class DateSerializer extends Serializer[Date] {
- private val DateClass = classOf[Date]
-
- def deserialize(implicit format: Formats) = {
- case (TypeInfo(DateClass, _), json) => json match {
- case JObject(List(JField("$dt", JString(s)))) =>
- format.dateFormat.parse(s).getOrElse(throw new MappingException("Can't parse "+ s + " to Date"))
- case x => throw new MappingException("Can't convert " + x + " to Date")
- }
- }
-
- def serialize(implicit format: Formats) = {
+ ))
+
+ class DateSerializer extends CustomSerializer[Date](format => (
+ {
+ case JObject(List(JField("$dt", JString(s)))) =>
+ format.dateFormat.parse(s).getOrElse(throw new MappingException("Can't parse "+ s + " to Date"))
+ },
+ {
case x: Date => JObject(JField("$dt", JString(format.dateFormat.format(x))) :: Nil)
}
- }
+ ))
class IndexedSeqSerializer extends Serializer[IndexedSeq[_]] {
def deserialize(implicit format: Formats) = {

0 comments on commit a8ec5d8

Please sign in to comment.