All Downloads are FREE. Search and download functionalities are using the official Maven repository.

conversions.ScalaConversions.scala Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2010 MongoDB, Inc. 
 * Copyright (c) 2009, 2010 Novus Partners, Inc. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For questions and comments about this product, please see the project page at:
 *
 * http://github.com/mongodb/casbah
 *
 */

package com.mongodb.casbah.commons
package conversions
package scala

import com.mongodb.casbah.commons.Imports._
import com.mongodb.casbah.commons.Logging

import org.bson.{ BSON, Transformer }

import com.github.nscala_time.time.Imports._

/**
 * " Register" Object, calls the registration methods.
 *
 * By default does not include JodaDateTime as this may be undesired behavior.
 * If you want JodaDateTime support, please use the RegisterJodaTimeConversionHelpers Object
 *
 * @since 1.0
 * @see RegisterJodaTimeConversionHelpers
 */
object RegisterConversionHelpers extends Serializers
    with Deserializers {
  def apply() {
    log.debug("Registering Scala Conversions.")
    super.register()
  }
}

/**
 * "DeRegister" Object, calls the unregistration methods.
 *
 * @since 1.0
 */
@deprecated("Be VERY careful using this - it will remove ALL of Casbah's loaded BSON Encoding & Decoding hooks at " +
  "runtime. If you need to clear Joda Time use DeregisterJodaTimeConversionHelpers.", "2.0")
object DeregisterConversionHelpers extends Serializers
    with Deserializers {
  def apply() {
    log.debug("Deregistering Scala Conversions.")
    // TODO - Figure out how to clear specific hooks as this clobbers everything.
    log.warning("Clobbering Casbah's Registered BSON Type Hooks (EXCEPT Joda Time).  Reregister any specific ones you may need.")
    super.unregister()
  }
}

/**
 * Converters for reading Scala types from MongoDB
 *
 * These should be setup in a way which requires
 * an explicit invocation / registration of individual
 * deserializers, else unexpected behavior will occur.
 *
 * Because it's likely to be controversial, JodaDateTime is NOT mixed in by default.
 *
 * @since 1.0
 */
trait Deserializers extends MongoConversionHelper {
  override def register() {
    log.debug("Deserializers for Scala Conversions registering")
    super.register()
  }

  override def unregister() {
    super.unregister()
  }
}

/**
 * Converters for saving Scala types to MongoDB
 *
 * For the most part these are 'safe' to enable automatically,
 * as they won't break existing code.
 * Be very careful with the deserializers however as they can come with
 * unexpected behavior.
 *
 * Because it's likely to be controversial, JodaDateTime is NOT mixed in by default.
 *
 * @since 1.0
 */
trait Serializers extends MongoConversionHelper
    with ScalaRegexSerializer
    with ScalaCollectionSerializer
    with ScalaProductSerializer
    with OptionSerializer {
  override def register() {
    log.debug("Serializers for Scala Conversions registering")
    super.register()
  }

  override def unregister() {
    super.unregister()
  }
}

trait OptionSerializer extends MongoConversionHelper {
  private val transformer = new Transformer {
    log.trace("Encoding a Scala Option[].")

    // scalastyle:off null
    def transform(o: AnyRef): AnyRef = o match {
      case Some(x) => x.asInstanceOf[AnyRef]
      case None    => null
      case _       => o
    }
    // scalastyle:on null

  }

  override def register() {
    log.debug("Setting up OptionSerializer")

    BSON.addEncodingHook(classOf[_root_.scala.Option[_]], transformer)

    super.register()
  }
}

object RegisterJodaTimeConversionHelpers extends JodaDateTimeHelpers {
  def apply() {
    log.debug("Registering  Joda Time Scala Conversions.")
    super.register()
  }
}

object DeregisterJodaTimeConversionHelpers extends JodaDateTimeHelpers {
  def apply() {
    log.debug("Unregistering Joda Time Scala Conversions.")
    super.unregister()
  }
}

trait JodaDateTimeHelpers extends JodaDateTimeSerializer with JodaDateTimeDeserializer

trait JodaDateTimeSerializer extends MongoConversionHelper {

  private val encodeTypeDateTime = classOf[DateTime]
  private val encodeTypeLocalDateTime = classOf[LocalDateTime]

  /** Encoding hook for MongoDB To be able to persist JodaDateTime DateTime to MongoDB */
  private val transformer = new Transformer {
    log.trace("Encoding a JodaDateTime DateTime.")

    def transform(o: AnyRef): AnyRef = o match {
      case d: DateTime      => d.toDate // Return a JDK Date object which BSON can encode
      case l: LocalDateTime => l.toDateTime.toDate
      case _                => o
    }

  }

  override def register() {
    log.debug("Hooking up Joda DateTime serializer.")

    /** Encoding hook for MongoDB To be able to persist JodaDateTime DateTime to MongoDB */
    BSON.addEncodingHook(encodeTypeDateTime, transformer)
    BSON.addEncodingHook(encodeTypeLocalDateTime, transformer)
    super.register()
  }

  override def unregister() {
    log.debug("De-registering Joda DateTime serializer.")
    BSON.removeEncodingHooks(encodeTypeDateTime)
    BSON.removeEncodingHooks(encodeTypeLocalDateTime)
    super.unregister()
  }
}

trait JodaDateTimeDeserializer extends MongoConversionHelper {

  private val encodeType = classOf[java.util.Date]
  private val transformer = new Transformer {
    log.trace("Decoding JDK Dates .")

    def transform(o: AnyRef): AnyRef = o match {
      case jdkDate: java.util.Date => new DateTime(jdkDate)
      case d: DateTime             => d
      case l: LocalDateTime        => l.toDateTime
      case _                       => o
    }
  }

  override def register() {
    log.debug("Hooking up Joda DateTime deserializer")

    /** Encoding hook for MongoDB To be able to read JodaDateTime DateTime from MongoDB's BSON Date */
    BSON.addDecodingHook(encodeType, transformer)
    super.register()
  }

  override def unregister() {
    log.debug("De-registering Joda DateTime deserializer.")
    BSON.removeDecodingHooks(encodeType)
    super.unregister()
  }
}

trait JodaLocalDateTimeHelpers extends JodaLocalDateTimeSerializer with JodaLocalDateTimeDeserializer

trait JodaLocalDateTimeSerializer extends MongoConversionHelper {

  private val encodeTypeDateTime = classOf[DateTime]
  private val encodeTypeLocalDateTime = classOf[LocalDateTime]

  /** Encoding hook for MongoDB To be able to persist JodaDateTime DateTime to MongoDB */
  private val transformer = new Transformer {
    log.trace("Encoding a JodaLocalDateTime DateTime.")

    def transform(o: AnyRef): AnyRef = o match {
      case d: DateTime      => d.toLocalDateTime.toDate // Return a JDK Date object which BSON can encode
      case l: LocalDateTime => l.toDate
      case _                => o
    }

  }

  override def register() {
    log.debug("Hooking up Joda LocalDateTime serializer.")

    /** Encoding hook for MongoDB To be able to persist JodaLocalDateTime DateTime to MongoDB */
    BSON.addEncodingHook(encodeTypeDateTime, transformer)
    BSON.addEncodingHook(encodeTypeLocalDateTime, transformer)
    super.register()
  }

  override def unregister() {
    log.debug("De-registering Joda LocalDateTime serializer.")
    BSON.removeEncodingHooks(encodeTypeDateTime)
    BSON.removeEncodingHooks(encodeTypeLocalDateTime)
    super.unregister()
  }
}

trait JodaLocalDateTimeDeserializer extends MongoConversionHelper {

  private val encodeType = classOf[java.util.Date]
  private val transformer = new Transformer {
    log.trace("Decoding JDK Dates .")

    def transform(o: AnyRef): AnyRef = o match {
      case jdkDate: java.util.Date => new LocalDateTime(jdkDate)
      case d: DateTime             => d.toLocalDateTime
      case l: LocalDateTime        => l
      case _                       => o
    }
  }

  override def register() {
    log.debug("Hooking up Joda DateTime deserializer")

    /** Encoding hook for MongoDB To be able to read JodaDateTime DateTime from MongoDB's BSON Date */
    BSON.addDecodingHook(encodeType, transformer)
    super.register()
  }

  override def unregister() {
    log.debug("De-registering Joda DateTime deserializer.")
    BSON.removeDecodingHooks(encodeType)
    super.unregister()
  }
}

trait ScalaRegexSerializer extends MongoConversionHelper {
  private val transformer = new Transformer {
    log.trace("Encoding a Scala RegEx.")

    def transform(o: AnyRef): AnyRef = o match {
      case sRE: _root_.scala.util.matching.Regex => sRE.pattern
      case _                                     => o
    }

  }

  override def register() {
    log.debug("Setting up ScalaRegexSerializers")

    log.debug("Hooking up scala.util.matching.Regex serializer")

    /** Encoding hook for MongoDB to translate a Scala Regex to a JAva Regex (which Mongo will understand) */
    BSON.addEncodingHook(classOf[_root_.scala.util.matching.Regex], transformer)

    super.register()
  }
}

object RegisterJodaLocalDateTimeConversionHelpers extends JodaLocalDateTimeHelpers {
  def apply() {
    log.debug("Registering  Joda Time Scala Conversions.")
    super.register()
  }
}

object DeregisterJodaLocalDateTimeConversionHelpers extends JodaLocalDateTimeHelpers {
  def apply() {
    log.debug("Unregistering Joda Time Scala Conversions.")
    super.unregister()
  }
}

/**
 * Implementation which is aware of the possible conversions in scalaj-collection and attempts to Leverage it...
 * Not all of these may be serializable by Mongo However... this is a first pass attempt at moving them to Java types
 */
trait ScalaCollectionSerializer extends MongoConversionHelper {

  private val transformer = new Transformer {

    import _root_.scala.collection.JavaConverters._

    def transform(o: AnyRef): AnyRef = o match {
      case mdbo: MongoDBObject => mdbo.underlying // MongoDBObject is a custom Iterable
      case mdbl: MongoDBList => mdbl.underlying // MongoDBList is a custom Iterable
      case m: _root_.scala.collection.mutable.Map[_, _] => m.asJava // Maps are Iterable but we need to keep them Map like
      case m: _root_.scala.collection.Map[_, _] => m.asJava // Maps are Iterable but we need to keep them Map like
      case i: _root_.scala.collection.Iterable[_] => i.asJava
      case i: _root_.scala.collection.Iterator[_] => i.asJava
      case _ => o
    }
  }

  override def register() {
    log.debug("Setting up ScalaCollectionSerializer")
    BSON.addEncodingHook(classOf[_root_.scala.collection.Iterator[_]], transformer)
    BSON.addEncodingHook(classOf[_root_.scala.collection.Iterable[_]], transformer)
    super.register()
  }
}

trait ScalaProductSerializer extends MongoConversionHelper {

  import _root_.scala.collection.JavaConverters._

  private val transformer = new Transformer {
    log.trace("Encoding a Scala Product.")

    def transform(o: AnyRef): AnyRef = o match {
      case l: java.util.List[_] => l // Ignore converted Products that are wrapped java.util.Lists
      case p: Product           => p.productIterator.toList.asJava
      case _                    => o
    }
  }

  override def register() {
    log.debug("Setting up ScalaProductSerializer")
    BSON.addEncodingHook(classOf[Product], transformer)
    super.register()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy