Project Polygene has retired. For details please refer to its Attic page.
Scala Support
Zest™
Introduction
Tutorials
Javadoc
Samples
Core
Libraries
Extensions
Tools
Glossary 

Scala Support

code

docs

tests

The Scala Support Library allows Fragments and Composites to be written as Scala traits.

Table 24. Artifact

Group IDArtifact IDVersion

org.qi4j.library

org.qi4j.library.lang-scala

2.1


The Scala Support Library is a Generic mixin class that implements Composites by delegating to Scala traits.

Composition

Example mixin declaration:

trait HelloWorldMixin2
{
  def sayHello(@MaxLength(10) name: String ): String = "Hello " + name
}

Example composite declaration:

@Concerns(Array(classOf[ HelloThereConcern ]))
trait HelloWorldComposite
  extends TransientComposite with HelloWorldMixin with HelloWorldMixin2

Example typed concern:

class HelloThereConcern
  extends ConcernOf[ HelloWorldMixin2 ] with HelloWorldMixin2
{
  override def sayHello(name: String ) = next.sayHello("there " + name)
}

Example generic concern with filter:

@AppliesTo(Array(classOf[ StringFilter ]))
class ExclamationGenericConcern
  extends GenericConcern
{
  def invoke(composite: AnyRef, method: Method, args: Array[ AnyRef ] ) = next.invoke(composite, method, args) + "!"
}

class StringFilter
  extends AppliesToFilter
{
  def appliesTo(method: Method, mixin: Class[ _ ], compositeType: Class[ _ ], fragmentClass: Class[ _ ] ) = method
    .getReturnType
    .equals(classOf[ String ])
}

And the assembly code. Note that the ScalaTraitMixin must be added.

module.transients( HelloWorldComposite.class, HelloWorldComposite2.class ).
    withMixins( ScalaTraitMixin.class ).
    withConcerns( ExclamationGenericConcern.class );

That pretty much covers the domain model part. Usage from Java is transparent, since it looks just like interfaces and classes.

Entity composites

The following example separate between command interface (suggestions to change), events (after the fact), and data, so they are in three separate traits below. Only commands are called by client code.

trait TestEntity
  extends EntityComposite with Commands with Events with Data

trait Commands
{
  self: Events =>
  def updateFoo(newValue: String )
  {
    // Call "injected" service
    val repeated = testService.repeat(newValue)

    // Check here if input is ok
    updatedFoo(repeated)
  }

  // Service injection - this is really a method call to the ServiceFinder of the composite
  @Service
  def testService: TestService
}

// Raw data of entity goes here
trait Data
{
  @UseDefaults
  def foo: Property[ String ]

  // Define property
  def foo_=(v: String ) { foo.set(v)  } // Operator overloading for =
}

trait Events
{
  self: Data =>
  def updatedFoo(newValue: String )
  {
    // Register change by modifying state
    foo = newValue
  }
}

The self operator thing solves the @This injection requirements, although it doesn’t do private injections (i.e. the Entity has to extend Events and Data for it to work).

Everything is statically typed.

And the corresponding assembly code:

module.entities( TestEntity.class ).withMixins( ScalaTraitMixin.class );

Services composites

The following example is a pretty simple service written as a Scala trait:

trait TestService
  extends ServiceComposite
{
  def repeat(input: String ): String = input + input
}

And the corresponding assembly code:

module.services( TestService.class ).withMixins( ScalaTraitMixin.class );