Implementing my domain model in scala using case classes I got
abstract class Entity {
val _id: Option[BSONObjectID]
val version: Option[BSONLong]
}
and several case classes defining the different entities like
case class Person (
_id: Option[BSONObjectID],
name: String,
version: Option[BSONLong]
) extends Entity
What I need is a way to set the _id and version later on from a generic method which operates on an Entity because I have to share this behavior over all Entities and want to avoid writing it down hundreds of times ;-). I would love to be able to
def createID(entity: Entity): Entity = {
entity.copy(_id = ..., version = ...)
}
...but of course this does not compile since an Entity has no copy-method. It is generated for each single case class by the compiler...
What is the best way to achieve this in scala?
To prevent somebody asking: I have to use case classes since this is what the third-party-library is extracting for me from the requests I get and the case class instances are what is serialized back to BSON / MongoDB later on...
Indeed one can find a way to implement something like this at
Create common trait for all case classes supporting copy(id=newId) method
but since it is quite complicated for my use case I would prefer just to create two new classes
class MongoId(var id : BSONObjectID = null) {
def generate = {
id = BSONObjectID.generate
}
}
class MongoVersion(var version: Long = 0) {
def update = {
version = System.currentTimeMillis
}
}
and implemented the shared behavior regarding these fields there. Of course you have to change the definition of your base class accordingly:
abstract class Entity {
def _id: MongoId
def version: MongoVersion
}
To make it clear: This works only if the behavior you want to share over several case classes does only affect (in my case changes) one attribute ...
Would implementing a trait work?
trait MongoIdHandler {
def createId(entity : Entity) : Option[BSONObjectID] = { ..}
def setVersion(version : String) : Unit = { ..}
}
case class Person (..) with MongoIdHandler ..
If any of the instances require specialized versions of the id generator they can override the 'default' impl provided by the trait.
Related
I was wondering if anyone has any experience with creating a type-parametrized type hierarchy? I am fairly certain this is acheivable as a result of scala's pseudo-unification of packages & static objects.
The specific use case I have in mind is parametrizing an id type over an application framework so you can use your choice of int/long/java.util.UUID/BSONId/whatever. Consider as a rough example:
package foolib.generic
trait GenEntity[I] { def id: I }
trait GenRepository[I] { def getById(id: I): GenEntity[I] }
trait FooTaxonomy[I] {
type Entity = GenEntity[I]
type Repository = GenRepository[I]
object subpackage extends generic.subpackage.SubpackageTaxonomy[I]
}
You would then configure the hierarchy for use in a project with something like:
package object myprj {
object foolib extends foolib.generic.FooTaxonomy[java.util.UUID]
// Whee!
val someEntity = new myprj.foolib.Entity(java.util.UUID.randomUUID())
}
Are there any reasons this is a spectacularly bad idea? Any pitfalls/etc I should be aware of?
This approach would work but you may encounter problems when the number of type parameters increases. Perhaps a solution would be to use abstract type members instead of type parameters.
Another approach is to use the cake pattern which I think provides a better solution in your case. The exact logic of your code eludes me a bit, so this rewrite may not entirely represent your intention:
package foolib.generic
//defines common types used by all modules
trait CoreModule {
type Id // abstract type, not commited to any particular implementation
}
//module defining the EntityModule trait
trait EntityModule { this: CoreModule => //specifying core module as a dependency
trait GenEntity {
def id: Id
}
def mkEntity(id: Id): Entity //abstract way of creating an entity
}
//defines the GenRepository trait
trait RepositoryModule { this: EntityModule with CoreModule => //multiple dependencies
trait GenRepository {
def getById(id: Id): GenEntity
}
val repository: GenRepository //abstract way of obtaining a repository
}
//concrete implementation for entity
trait EntityImplModule extends EntityModule { this: CoreModule =>
case class Entity(val id: Id) extends GenEntity
def mkEntity(id: Id) = Entity(id)
}
//modules that provides a concrete implementation for GenRepository
trait RepositoryImplModule extends RepositoryModule { this: CoreModule with EntityModule =>
object RepositoryImpl extends GenRepository {
def getById(id: Id) = mkEntity(id)
}
}
//this unifies all your modules. You can also bind any dependencies and specify any types
object Universe
extends CoreModule
with EntityImplModule
with RepositoryImplModule {
type Id = java.util.UUID
val repository = RepositoryImpl
def mkEntity(id: Id) = Entity(id)
}
//usage
object Main {
import Universe._
import java.util.UUID
val entity = repository.getById(UUID.randomUUID())
println(entity.id)
}
This achieves your goal of creating an implementation independent of the concrete type Id and it also provides a nice way to do dependency injection.
The modules which provide a concrete implementation for GenRepository, for instance, may require a concrete type for Id. You can very well create another module which binds Id to a concrete type and make the RepositoryImplModule depend on the former module, thus specifying that this concrete implementation of GenRepository will work only for a certain type of ids.
The Cake pattern is very powerful and has many variations. This video explains it quite well, I recommend you watch it if you are interested in this solution:
Cake Pattern: The Bakery from the Black Lagoon
Schema.org is markup vocabulary (for the web) and defines a number of types in terms of properties (no methods). I am currently trying to model parts of that schema in Scala as internal model classes to be used in conjunction with a document-oriented database (MongoDB) and a web framework.
As can be seen in the definition of LocalBusiness, schema.org uses multiple inheritance to also include properties from the "Place" type. So my question is: How would you model such a schema in Scala?
I have come up with two solutions so far. The first one use regular classes to model a single inheritance tree and uses traits to mixin those additional properties.
trait ThingA {
var name: String = ""
var url: String = ""
}
trait OrganizationA {
var email: String = ""
}
trait PlaceA {
var x: String = ""
var y: String = ""
}
trait LocalBusinessA {
var priceRange: String = ""
}
class OrganizationClassA extends ThingA with OrganizationA {}
class LocalBusinessClassA extends OrganizationClassA with PlaceA with LocalBusinessA {}
The second version tries to use case classes. However, since case class inheritance is deprecated, I cannot model the main hierarchy so easily.
trait ThingB {
val name: String
}
trait OrganizationB {
val email: String
}
trait PlaceB {
val x: String
val y: String
}
trait LocalBusinessB {
val priceRange: String
}
case class OrganizationClassB(val name: String, val email: String) extends ThingB with OrganizationB
case class LocalBusinessClassB(val name: String, val email: String, val x: String, val y: String, val priceRange: String) extends ThingB with OrganizationB with PlaceB with LocalBusinessB
Is there a better way to model this? I could use composition similar to
case class LocalBusinessClassC(val thing:ThingClass, val place: PlaceClass, ...)
but then of course, LocalBusiness cannot be used when a "Place" is expected, for example when I try to render something on Google Maps.
What works best for you depends greatly on how you want to map your objects to the underlying datastore.
Given the need for multiple inheritance, and approach that might be worth considering would be to just use traits. This gives you multiple inheritance with the least amount of code duplication or boilerplating.
trait Thing {
val name: String // required
val url: Option[String] = None // reasonable default
}
trait Organization extends Thing {
val email: Option[String] = None
}
trait Place extends Thing {
val x: String
val y: String
}
trait LocalBusiness extends Organization with Place {
val priceRange: String
}
Note that Organization extends Thing, as does Place, just as in schema.org.
To instantiate them, you create anonymous inner classes that specify the values of all attributes.
object UseIt extends App {
val home = new Place {
val name = "Home"
val x = "-86.586104"
val y = "34.730369"
}
val oz = new Place {
val name = "Oz"
val x = "151.206890"
val y = "-33.873651"
}
val paulis = new LocalBusiness {
val name = "Pauli's"
override val url = "http://www.paulisbarandgrill.com/"
val x = "-86.713660"
val y = "34.755092"
val priceRange = "$$$"
}
}
If any fields have a reasonable default value, you can specify the default value in the trait.
I left fields without value as empty strings, but it probably makes more sense to make optional fields of type Option[String], to better indicate that their value is not set. You liked using Option, so I'm using Option.
The downside of this approach is that the compiler generates an anonymous inner class every place you instantiate one of the traits. This could give you an explosion of .class files. More importantly, though, it means that different instances of the same trait will have different types.
Edit:
In regards to how you would use this to load objects from the database, that depends greatly on how you access your database. If you use an object mapper, you'll want to structure your model objects in the way that the mapper expects them to be structured. If this sort of trick works with your object mapper, I'll be surprised.
If you're writing your own data access layer, then you can simply use a DAO or repository pattern for data access, putting the logic to build the anonymous inner classes in there.
This is just one way to structure these objects. It's not even the best way, but it demonstrates the point.
trait Database {
// treats objects as simple key/value pairs
def findObject(id: String): Option[Map[String, String]]
}
class ThingRepo(db: Database) {
def findThing(id: String): Option[Thing] = {
// Note that in this way, malformed objects (i.e. missing name) simply
// return None. Logging or other responses for malformed objects is left
// as an exercise :-)
for {
fields <- db.findObject(id) // load object from database
name <- field.get("name") // extract required field
} yield {
new Thing {
val name = name
val url = field.get("url")
}
}
}
}
There's a bit more to it than that (how you identify objects, how you store them in the database, how you wire up repository, how you'll handle polymorphic queries, etc.). But this should be a good start.
After some fiddling with scala I came to that solution for creating new objects from given type
object Entity {
def get[T <: Entity: ClassManifest]: T = {
val entity = implicitly[ClassManifest[T]].erasure.getConstructors()(0).newInstance().asInstanceOf[T]
/** some stuff **/
entity
}
}
abstract class Entity {
}
class Implementation extends Entity {
}
and then usage:
var e = Entity.get[Implementation]
My questions
is that ok or there is some different way of doing that (i am using scala 2.9.2 now)?
Is there something like Class.forName which allows to get type from its name? (or more generally, can I use type as variable?)
So one of the problems with StackOverflow is that no one is going to give me points for saying "Wow, that's clever. For god's sake don't ever do that or anything like it." Nonetheless, as a senior architect, that appears to be most of my job.
If you are using reflection outside or a library, or as a reason for interacting with a library, you're doing it wrong. So stop it.
Alternatively, you could pass the Class[T]:
object Entity {
def get[T <: Entity](e: Class[T]): T = {
val entity = e.getConstructors()(0).newInstance().asInstanceOf[T]
/** some stuff **/
entity
}
}
var e1 = Entity.get(classOf[Implementation])
You can use Class.forName, but you would lose type-safety (since the string className could be anything, not just an Entity subclass) and I think your return type would have to be Entity.
I'm in the process of learning Scala for a new project having come from Rails. I've defined a type that is going to be used in a number of my models which can basically be thought of as collection of 'attributes'. It's basically just a wrapper for a hashmap that delegates most of its responsibilities to it:
case class Description(attributes: Map[String, String]) {
override def hashCode: Int = attributes.hashCode
override def equals(other: Any) = other match {
case that: Description => this.attributes == that.attributes
case _ => false
}
}
So I would then define a model class with a Description, something like:
case class Person(val name: String, val description: Description)
However, when I persist a Person with a SalatDAO I end up with a document that looks like this:
{
name : "Russell",
description:
{
attributes:
{
hair: "brown",
favourite_color: "blue"
}
}
}
When in actual fact I don't need the nesting of the attributes tag in the description tag - what I actually want is this:
{
name : "Russell",
description:
{
hair: "brown",
favourite_color: "blue"
}
}
I haven't tried, but I reckon I could get that to work if I made Description extend a Map rather than contain one, but I'd rather not, because a Description isn't a type of Map, it's something which has some of the behaviour of a Map as well as other behaviour of its own I'm going to add later. Composition over inheritance and so on.
So my question is, how can I tell Salat (or Casbah, I'm actually a bit unclear as to which is doing the conversion as I've only just started using them) how to serialize and deserialize the Description class? In the casbah tutorial here it says:
It is also possible to create your own custom type serializers and
deserializers. See Custom Serializers and Deserializers.
But this page doesn't seem to exist. Or am I going about it the wrong way? Is there actually a really simple way to indicate this is what I want to happen, an annotation or something? Or can I simply delegate the serialization to the attributes map in some way?
EDIT: After having a look at the source for the JodaTime conversion helper I've tried the following but have had no luck getting it to work yet:
import org.bson.{ BSON, Transformer }
import com.mongodb.casbah.commons.conversions.MongoConversionHelper
object RegisterCustomConversionHelpers extends Serializers
with Deserializers {
def apply() = {
super.register()
}
}
trait Serializers extends MongoConversionHelper
with DescriptionSerializer {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait Deserializers extends MongoConversionHelper {
override def register() = {
super.register()
}
override def unregister() = {
super.unregister()
}
}
trait DescriptionSerializer extends MongoConversionHelper {
private val transformer = new Transformer {
def transform(o: AnyRef): AnyRef = o match {
case d: Description => d.attributes.asInstanceOf[AnyRef]
case _ => o
}
}
override def register() = {
BSON.addEncodingHook(classOf[Description], transformer)
super.register()
}
}
When I call RegisterCustomConversionHelpers() then save a Person I don't get any errors, it just has no effect, saving the document the same way as ever. This also seems like quite a lot to have to do for what I want.
Salat maintainer here.
I don't understand the value of Description as a wrapper here. It wraps a map of attributes, overrides the default equals and hashcode impl of a case class - which seems unnecessary since the impl is delegated to the map anyhow and that is exactly what the case class does anyway - and introduces an additional layer of indirection to the serialized object.
Have you considered just:
case class Person(val name: String, val description: Map[String, String])
This will do exactly what you want out of box.
In another situation I would recommend a simple type alias but unfortunately Salat can't support type aliases right now due to some issues with how they are depicted in pickled Scala signatures.
(You probably omitted this from your example from brevity, but it is best practice for your Mongo model to have an _id field - if you don't, the Mongo Java driver will supply one for you)
There is a working example of a custom BSON hook in the salat-core test package (it handles java.net.URL). It could be that your hook is not working simply because you are not registering it in the right place? But still, I would recommend getting rid of Description unless it is adding some value that is not evident from your example above.
Based on #prasinous' answer I decided this wasn't going to be that easy so I've changed my design a bit to the following, which pretty much gets me what I want. Rather than persisting the Description as a field I persist a vanilla map then mix in a Described trait to the model classes I want to have a description, which automatically converts the map to Description when the object is created. Would appreciate it if anyone can point out any obvious problems to this approach or any suggestions for improvement.
class Description(val attributes: Map[String, String]){
//rest of class omitted
}
trait Described {
val attributes: Map[String, String]
val description = new Description(attributes)
}
case class Person(name: String, attributes: Map[String, String]) extends Described
Let there a few separate DAO classes OrderDAO, ProductDAO, and CustomerDAO that store/retrieve data in the database and share a single instance DataSource (the database connection factory).
In order to create a DataSource instance and plug it in DAOs we usually use Spring DI. Now I would like to do that in Scala without any DI framework.
I've read about the cake pattern, and it looks like I should do the following:
trait DatabaseContext { val dataSource:Datasource }
trait OrderDAO {this:DatabaseContext =>
... // use dataSource of DatabaseContext
}
trait ProductDAO {this:DatabaseContext =>
... // use dataSource of DatabaseContext
}
object DAOImpl extends OrderDAO with ProductDAO with DatabaseContext {
val dataSource = ... // init the data source
}
Do I understand the cake pattern correctly?
Can I implement these DAOs differently using the cake pattern ?
What does it provide that DI frameworks like Spring do not ?
How can I create separate OrderDAOImpl and ProductDAOImpl objects sharing the same DataSource instance instead of one big DAOImpl?
The advantages of the cake pattern are:
Unlike configuration-file-based DI solutions, matching contracts to
implementations is done at compile time, which reduces class-finding
and compatibility issues. However, many DI engines have an
alternative in-code configuration feature
No third-party libraries
are used. Self-type annotations which let you use the pattern are a
native language feature. No special syntax is used to retrieve the
implementation of the contract
Forgetting to specify an
implementation for a component needed by another component results in
a runtime error - just check this article
http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html
and try not specifying one of the components or specifying a
trait instead of a concrete class in any of the cake pattern
examples or even forgetting to initialize a val corresponding to a component needed
However, to experience these advantages, you need to more strictly adhere to the architecture of the pattern - check the same article and note the wrapping traits that contain the actual contracts and implementations.
Your examples do not seem to be strictly the cake pattern. In your case you could've just used inheritance to create implementations for your traits and use separate classes for each DAO component. In the cake pattern the consuming code would be a component just like the DAO code, and the code assembling the dependencies together would stand alone from it.
To illustrate the cake pattern, you would have to add consuming classes (domain layer or UI layer) to your example. Or it the case your DAO components accessed each other's features you could illustrate the cake pattern on you DAO alone.
to make it short,
trait OrderDAOComponent {
val dao: OrderDAO
trait OrderDAO {
def create: Order
def delete(id: Int): Unit
//etc
}
}
trait OrderDAOComponentImpl extends OrderDAOComponent {
class OrderDAOJDBCImpl extends OrderDAO {
def create: Order = {/*JDBC-related code here*/}
def delete(id: Int) {/*JDBC-related code here*/}
//etc
}
}
//This one has a dependency
trait OrderWebUIComponentImpl {
this: OrderDAOComponent =>
class OrderWebUI {
def ajaxDelete(request:HttpRequest) = {
val id = request.params("id").toInt
try {
dao.delete(id)
200
}
catch {
case _ => 500
}
}
}
}
//This matches contracts to implementations
object ComponentRegistry extends
OrderDAOComponentImpl with
OrderWebUIComponentImpl
{
val dao = new OrderDAOJDBCImpl
val ui = new OrderWebUI
}
//from some front-end code
val status = ComponentRegistry.ui.ajaxDelete(request)
More on your example. I think it could be more like cake if:
trait DatabaseContext { val dataSource:Datasource }
trait OrderDAOComponent {this:DatabaseContext =>
trait OrderDAOImpl {
... // use dataSource of DatabaseContext
}
}
trait ProductDAOComponent {this:DatabaseContext =>
trait ProductDAOImpl {
... // use dataSource of DatabaseContext
}
}
object Registry extends OrderDAOComponent with ProductDAOComponent with DatabaseContextImpl {
val dataSource = new DatasourceImpl //if Datasource is a custom trait, otherwise wrapping needed
val orderDAO = new OrderDAOImpl
val productDAO = new ProductDAOImpl
}
//now you may use them separately
Registry.orderDAO.//
Maybe:
Statically checked at compile time.