• Stars
    star
    1,252
  • Rank 36,547 (Top 0.8 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created over 11 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lightweight and Nonintrusive Scala Dependency Injection Library

MacWire

Table of Contents

MacWire

Ideas, suggestions, problems, questions Maven Central

MacWire generates new instance creation code of given classes, using values in the enclosing type for constructor parameters, with the help of Scala Macros.

For a general introduction to DI in Scala, take a look at the Guide to DI in Scala, which also features MacWire.

MacWire helps to implement the Dependency Injection (DI) pattern, by removing the need to write the class-wiring code by hand. Instead, it is enough to declare which classes should be wired, and how the instances should be accessed (see Scopes).

Classes to be wired should be organized in "modules", which can be Scala traits, classes or objects. Multiple modules can be combined using inheritance or composition; values from the inherited/nested modules are also used for wiring.

MacWire can be in many cases a replacement for DI containers, offering greater control on when and how classes are instantiated, typesafety and using only language (Scala) mechanisms.

Example usage:

class DatabaseAccess()
class SecurityFilter()
class UserFinder(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter)
class UserStatusReader(userFinder: UserFinder)

trait UserModule {
    import com.softwaremill.macwire._

    lazy val theDatabaseAccess   = wire[DatabaseAccess]
    lazy val theSecurityFilter   = wire[SecurityFilter]
    lazy val theUserFinder       = wire[UserFinder]
    lazy val theUserStatusReader = wire[UserStatusReader]
}

will generate:

trait UserModule {
    lazy val theDatabaseAccess   = new DatabaseAccess()
    lazy val theSecurityFilter   = new SecurityFilter()
    lazy val theUserFinder       = new UserFinder(theDatabaseAccess, theSecurityFilter)
    lazy val theUserStatusReader = new UserStatusReader(theUserFinder)
}

For testing, just extend the base module and override any dependencies with mocks/stubs etc, e.g.:

trait UserModuleForTests extends UserModule {
    override lazy val theDatabaseAccess = mockDatabaseAccess
    override lazy val theSecurityFilter = mockSecurityFilter
}

The core library has no dependencies.

For more motivation behind the project see also these blogs:

How wiring works

For each constructor parameter of the given class, MacWire tries to find a value conforming to the parameter's type in the enclosing method and trait/class/object:

  • first it tries to find a unique value declared as a value in the current block, argument of enclosing methods and anonymous functions.
  • then it tries to find a unique value declared or imported in the enclosing type
  • then it tries to find a unique value in parent types (traits/classes)
  • if the parameter is marked as implicit, it is ignored by MacWire and handled by the normal implicit resolution mechanism

Here value means either a val or a no-parameter def, as long as the return type matches.

A compile-time error occurs if:

  • there are multiple values of a given type declared in the enclosing block/method/function's arguments list, enclosing type or its parents.
  • parameter is marked as implicit and implicit lookup fails to find a value
  • there is no value of a given type

The generated code is then once again type-checked by the Scala compiler.

Factories

A factory is simply a method. The constructor of the wired class can contain parameters both from the factory (method) parameters, and from the enclosing/super type(s).

For example:

class DatabaseAccess()
class TaxDeductionLibrary(databaseAccess: DatabaseAccess)
class TaxCalculator(taxBase: Double, taxDeductionLibrary: TaxDeductionLibrary)

trait TaxModule {
    import com.softwaremill.macwire._

    lazy val theDatabaseAccess      = wire[DatabaseAccess]
    lazy val theTaxDeductionLibrary = wire[TaxDeductionLibrary]
    def taxCalculator(taxBase: Double) = wire[TaxCalculator]
    // or: lazy val taxCalculator = (taxBase: Double) => wire[TaxCalculator]
}

will generate:

trait TaxModule {
    lazy val theDatabaseAccess      = new DatabaseAccess()
    lazy val theTaxDeductionLibrary = new TaxDeductionLibrary(theDatabaseAccess)
    def taxCalculator(taxBase: Double) =
       new TaxCalculator(taxBase, theTaxDeductionLibrary)
}

Factory methods

You can also wire an object using a factory method, instead of a constructor. For that, use wireWith instead of wire. For example:

class A()

class C(a: A, specialValue: Int)
object C {
  def create(a: A) = new C(a, 42)
}

trait MyModule {
  lazy val a = wire[A]
  lazy val c = wireWith(C.create _)
}

lazy val vs. val

It is safer to use lazy vals, as when using val, if a value is forward-referenced, it's value during initialization will be null. With lazy val the correct order of initialization is resolved by Scala.

Recursive wiring

When using wire and a value for a parameter can't be found, an error is reported. wireRec takes a different approach - it tries to recursively create an instance, using normal wiring rules. This allows to explicitly wire only those objects, which are referenced from the code, skipping helper or internal ones.

The previous example becomes:

class DatabaseAccess()
class SecurityFilter()
class UserFinder(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter)
class UserStatusReader(userFinder: UserFinder)

trait UserModule {
    import com.softwaremill.macwire._

    lazy val theUserStatusReader = wireRec[UserStatusReader]
}

and will generate:

trait UserModule {
    lazy val theUserStatusReader = new UserStatusReader(
		new UserFinder(new DatabaseAccess(), new SecurityFilter()))
}

This feature is inspired by @yakivy's work on jam.

Autowire

Warning: autowire is an experimental feature, if you have any feedback regarding its usage, let us know! Future releases might break source/binary compatibility. It is available for Scala 2 only for now.

Dependency: "com.softwaremill.macwire" %% "macrosautocats" % "2.5.9"

In case you need to build an instance from some particular instances and factory methods you can leverage autowire. This feature is intended to integrate with effect-management libraries (currently we support cats-effect).

autowire takes as an argument a list of arguments which may contain:

  • values (e.g. new A())
  • factory methods (e.g. C.create _)
  • factory methods that return cats.effect.Resource or cats.effect.IO (e.g. C.createIO _)
  • cats.effect.Resource (e.g. cats.effect.Resource[IO].pure(new A()))
  • cats.effect.IO (e.g. cats.effect.IO.pure(new A()))

Using the dependencies from the given arguments it creates an instance of the given type. Any missing instances are created using their primary constructor, provided that the dependencies are met. If this is not possible, a compile-time error is reported. In other words, a wireRec is performed, bypassing the instances search phase.

The result of the wiring is always wrapped in cats.effect.Resource. For example:

import cats.effect._

class DatabaseAccess()

class SecurityFilter private (databaseAccess: DatabaseAccess)
object SecurityFilter {
  def apply(databaseAccess: DatabaseAccess): SecurityFilter = new SecurityFilter(databaseAccess)
}

class UserFinder(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter)
class UserStatusReader(databaseAccess: DatabaseAccess, userFinder: UserFinder)

object UserModule {
  import com.softwaremill.macwire.autocats._

  val theDatabaseAccess: Resource[IO, DatabaseAccess] = Resource.pure(new DatabaseAccess())

  val theUserStatusReader: Resource[IO, UserStatusReader] = autowire[UserStatusReader](theDatabaseAccess)
}

will generate:

[...]
object UserModule {
  import com.softwaremill.macwire.autocats._

  val theDatabaseAccess: Resource[IO, DatabaseAccess] = Resource.pure(new DatabaseAccess())

  val theUserStatusReader: Resource[IO, UserStatusReader] = UserModule.this.theDatabaseAccess.flatMap(
    da => Resource.pure[IO, UserStatusReader](new UserStatusReader(da, new UserFinder(da, SecurityFilter.apply(da))))
  )
}

Composing modules

Modules (traits or classes containing parts of the object graph) can be combined using inheritance or composition. The inheritance case is straightforward, as wire simply looks for values in parent traits/classes. With composition, you need to tell MacWire that it should look inside the nested modules.

To do that, you can use imports:

class FacebookAccess(userFind: UserFinder)

class UserModule {
  lazy val userFinder = ... // as before
}

class SocialModule(userModule: UserModule) {
  import userModule._

  lazy val facebookAccess = wire[FacebookAccess]
}

Or, if you are using that pattern a lot, you can annotate your modules using @Module, and they will be used when searching for values automatically:

class FacebookAccess(userFind: UserFinder)

@Module
class UserModule { ... } // as before

class SocialModule(userModule: UserModule) {
  lazy val facebookAccess = wire[FacebookAccess]
}

Warning: the @Module annotation is an experimental feature, if you have any feedback regarding its usage, let us know!

Scopes

There are two "built-in" scopes, depending on how the dependency is defined:

  • singleton: lazy val / val
  • dependent - separate instance for each dependency usage: def

MacWire also supports user-defined scopes, which can be used to implement request or session scopes in web applications. The proxy subproject defines a Scope trait, which has two methods:

  • apply, to create a scoped value
  • get, to get or create the current value from the scope

To define a dependency as scoped, we need a scope instance, e.g.:

trait WebModule {
   lazy val loggedInUser = session(new LoggedInUser)

   def session: Scope
}

With abstract scopes as above, it is possible to use no-op scopes for testing (NoOpScope).

There's an implementation of Scope targeted at classical synchronous frameworks, ThreadLocalScope. The apply method of this scope creates a proxy (using javassist); the get method stores the value in a thread local. The proxy should be defined as a val or lazy val.

In a web application, the scopes have to be associated and disassociated with storages. This can be done for example in a servlet filter. To implement a:

  • request scope, we need a new empty storage for every request. The associateWithEmptyStorage is useful here
  • session scope, the storage (a Map) should be stored in the HttpSession. The associate(Map) method is useful here

For example usage see the MacWire+Scalatra example sources.

You can run the example with sbt examples-scalatra/run and going to http://localhost:8080.

Note that the proxy subproject does not depend on MacWire core, and can be used stand-alone with manual wiring or any other frameworks.

Accessing wired instances dynamically

To integrate with some frameworks (e.g. Play 2) or to create instances of classes which names are only known at run-time (e.g. plugins) it is necessary to access the wired instances dynamically. MacWire contains a utility class in the util subproject, Wired, to support such functionality.

An instance of Wired can be obtained using the wiredInModule macro, given an instance of a module containing the wired object graph. Any vals, lazy vals and parameter-less defs (factories) from the module which are references will be available in the Wired instance.

The object graph in the module can be hand-wired, wired using wire, or a result of any computation.

Wired has two basic functionalities: looking up an instance by its class (or trait it implements), and instantiating new objects using the available dependencies. You can also extend Wired with new instances/instance factories.

For example:

// 1. Defining the object graph and the module
trait DatabaseConnector
class MysqlDatabaseConnector extends DatabaseConnector

class MyApp {
    def securityFilter = new SecurityFilter()
    val databaseConnector = new MysqlDatabaseConnector()
}

// 2. Creating a Wired instance
import com.softwaremill.macwire._
val wired = wiredInModule(new MyApp)

// 3. Dynamic lookup of instances
wired.lookup(classOf[SecurityFilter])

// Returns the mysql database connector, even though its type is MysqlDatabaseConnector, which is
// assignable to DatabaseConnector.
wired.lookup(classOf[DatabaseConnector])

// 4. Instantiation using the available dependencies
{
    package com.softwaremill
    class AuthenticationPlugin(databaseConnector: DatabaseConnector)
}

// Creates a new instance of the given class using the dependencies available in MyApp
wired.wireClassInstanceByName("com.softwaremill.AuthenticationPlugin")

Interceptors

MacWire contains an implementation of interceptors, which can be applied to class instances in the modules. Similarly to scopes, the proxy subproject defines an Interceptor trait, which has only one method: apply. When applied to an instance, it should return an instance of the same class, but with the interceptor applied.

There are two implementations of the Interceptor trait provided:

  • NoOpInterceptor: returns the given instance without changes
  • ProxyingInterceptor: proxies the instance, and returns the proxy. A provided function is called with information on the invocation

Interceptors can be abstract in modules. E.g.:

trait BusinessLogicModule {
   lazy val moneyTransferer = transactional(wire[MoneyTransferer])

   def transactional: Interceptor
}

During tests, you can then use the NoOpInterceptor. In production code or integration tests, you can specify a real interceptor, either by extending the ProxyingInterceptor trait, or by passing a function to the ProxyingInterceptor object:

object MyApplication extends BusinessLogicModule {
    lazy val tm = wire[TransactionManager]

    lazy val transactional = ProxyingInterceptor { ctx =>
        try {
            tm.begin()
            val result = ctx.proceed()
            tm.commit()

            result
        } catch {
            case e: Exception => tm.rollback()
        }
    }
}

The ctx is an instance of an InvocationContext, and contains information on the parameters passed to the method, the method itself, and the target object. It also allows to proceed with the invocation with the same or changed parameters.

For more general AOP, e.g. if you want to apply an interceptor to all methods matching a given pointcut expression, you should use AspectJ or an equivalent library. The interceptors that are implemented in MacWire correspond to annotation-based interceptors in Java.

Qualifiers

Sometimes you have multiple objects of the same type that you want to use during wiring. Macwire needs to have some way of telling the instances apart. As with other things, the answer is: types! Even when not using wire, it may be useful to give the instances distinct types, to get compile-time checking.

For that purpose Macwire includes support for tagging via scala-common, which lets you attach tags to instances to qualify them. This is a compile-time only operation, and doesn't affect the runtime. The tags are derived from Miles Sabin's gist.

To bring the tagging into scope, import com.softwaremill.tagging._.

Using tagging has two sides. In the constructor, when declaring a dependency, you need to declare what tag it needs to have. You can do this with the _ @@ _ type constructor, or if you prefer another syntax Tagged[_, _]. The first type parameter is the type of the dependency, the second is a tag.

The tag can be any type, but usually it is just an empty marker trait.

When defining the available instances, you need to specify which instance has which tag. This can be done with the taggedWith[_] method, which returns a tagged instance (A.taggedWith[T]: A @@ T). Tagged instances can be used as regular ones, without any constraints.

The wire macro does not contain any special support for tagging, everything is handled by subtyping. For example:

class Berry()
trait Black
trait Blue

case class Basket(blueberry: Berry @@ Blue, blackberry: Berry @@ Black)

lazy val blueberry = wire[Berry].taggedWith[Blue]
lazy val blackberry = wire[Berry].taggedWith[Black]
lazy val basket = wire[Basket]

Multiple tags can be combined using the andTaggedWith method. E.g. if we had a berry that is both blue and black:

lazy val blackblueberry = wire[Berry].taggedWith[Black].andTaggedWith[Blue]

The resulting value has type Berry @ (Black with Blue) and can be used both as a blackberry and as a blueberry.

Multi Wiring (wireSet)

Using wireSet you can obtain a set of multiple instances of the same type. This is done without constructing the set explicitly. All instances of the same type which are found by MacWire are used to construct the set.

Consider the below example. Let's suppose that you want to create a RockBand(musicians: Set[Musician]) object. It's easy to do so using the wireSet functionality:

trait Musician
class RockBand(musicians: Set[Musician])

trait RockBandModule {
  lazy val singer    = new Musician {}
  lazy val guitarist = new Musician {}
  lazy val drummer   = new Musician {}
  lazy val bassist   = new Musician {}

  lazy val musicians = wireSet[Musician] // all above musicians will be wired together
                                         // musicians has type Set[Musician]

  lazy val rockBand  = wire[RockBand]
}

Limitations

When:

  • referencing wired values within the trait/class/object
  • using multiple modules in the same compilation unit
  • using multiple modules with scopes

due to limitations of the current macros implementation in Scala (for more details see this discussion) to avoid compilation errors it is recommended to add type ascriptions to the dependencies. This is a way of helping the type-checker that is invoked by the macro to figure out the types of the values which can be wired.

For example:

class A()
class B(a: A)

// note the explicit type. Without it wiring would fail with recursive type compile errors
lazy val theA: A = wire[A]
// reference to theA; if for some reason we need explicitly write the constructor call
lazy val theB = new B(theA)

This is an inconvenience, but hopefully will get resolved once post-typer macros are introduced to the language.

Also, wiring will probably not work properly for traits and classes defined inside the containing trait/class, or in super traits/classes.

Note that the type ascription may be a subtype of the wired type. This can be useful if you want to expose e.g. a trait that the wired class extends, instead of the full implementation.

Akka integration

Macwire provides wiring suport for akka through the macrosAkka module. Here you can find example code. The module adds three macros wireAnonymousActor[A], wireActor[A] and wireProps[A] which help create instances of akka.actor.ActorRef and akka.actor.Props.

These macros require an ActoRefFactory (ActorSystem or Actor.context) to be in scope as a dependency. If actor's primary constructor has dependencies - they are required to be in scope as well.

Example usage:

import akka.actor.{Actor, ActorRef, ActorSystem}

class DatabaseAccess()
class SecurityFilter()
class UserFinderActor(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter) extends Actor {
  override def receive: Receive = {
    case m => // ...
  }
}

import com.softwaremill.macwire._
import com.softwaremill.macwire.akkasupport._

val theDatabaseAccess = wire[DatabaseAccess] //1st dependency for UserFinderActor
                                             //it compiles to: val theDatabaseAccess = new DatabaseAccess

val theSecurityFilter = wire[SecurityFilter] //2nd dependency for UserFinderActor
                                             //it compiles to: val theSecurityFilter = new SecurityFilter

val system = ActorSystem("actor-system") //there must be instance of ActoRefFactory in scope

val theUserFinder = wireActor[UserFinderActor]("userFinder")
//this compiles to:
//lazy val theUserFinder = system.actorOf(Props(classOf[UserFinderActor], theDatabaseAccess, theSecurityFilter), "userFinder")

In order to make it working all dependencies created Actor's (UserFinderActor's) primary constructor and instance of the akka.actor.ActorRefFactory must be in scope. In above example this is all true. Dependencies of the UserFinderActor are DatabaseAccess and SecurityFilter and they are in scope. The ActorRefFactory is in scope as well because ActorSystem which is subtype of it is there.

Creating actor within another actor is even simpler than in first example because we don't need to have ActorSystem in scope. The ActorRefFactory is here because Actor.context is subtype of it. Let's see this in action:

class UserStatusReaderActor(theDatabaseAccess: DatabaseAccess) extends Actor {
  val theSecurityFilter = wire[SecurityFilter]

  val userFinder = wireActor[UserFinderActor]("userFinder")
  //this compiles to:
  //val userFinder = context.actorOf(Props(classOf[UserFinderActor], theDatabaseAccess, theSecurityFilter), "userFinder")

  override def receive = ...
}

The difference is that previously macro expanded into system.actorOf(...) and when inside another actor it expanded into context.actorOf(...).

It's possible to create anonymous actors. wireAnonymousActor is for it:

val userFinder = wireAnonymousActor[UserFinderActor]
//this compiles to:
//val userFinder = context.actorOf(Props(classOf[UserFinderActor], theDatabaseAccess, theSecurityFilter))

How about creating akka.actor.Props? It's there and can be achieved by calling wireProps[A]. Wiring only Props can be handy when it's required to setup the Props before passing them to the actorOf(...) method.

Let's say we want to create some actor with router. It can be done as below:

val userFinderProps = wireProps[UserFinderActor] //create Props
  //This compiles to: Props(classOf[UserFinderActor], theDatabaseAccess, theSecurityFilter)
  .withRouter(RoundRobinPool(4)) //change it according requirements
val userFinderActor = system.actorOf(userFinderProps, "userFinder")  //create the actor

How about creating actors which depends on ActorRefs? The simplest way is to pass them as arguments to the constructor. But how to distinguish two actorRefs representing two different actors? They have the same type though.

class DatabaseAccessActor extends Actor { ... }
class SecurityFilterActor extends Actor { ... }
val db: ActorRef = wireActor[DatabaseAccessActor]("db")
val filter: ActorRef = wireActor[SecurityFilterActor]("filter")
class UserFinderActor(databaseAccess: ActorRef, securityFilter: ActorRef) extends Actor {...}
//val userFinder = wireActor[UserFinderActor] wont work here

We can't just call wireActor[UserFinderActor] because it's not obvious which instance of ActorRef is for databaseAccess and which are for securityFilter. They are both of the same type - ActorRef.

The solution for it is to use earlier described qualifiers. In above example solution for wiring may look like this:

sealed trait DatabaseAccess //marker type
class DatabaseAccessActor extends Actor { ... }
sealed trait SecurityFilter //marker type
class SecurityFilterActor extends Actor { ... }

val db: ActorRef @@ DatabaseAccess = wireActor[DatabaseAccessActor]("db").taggedWith[DatabaseAccess]
val filter: ActorRef @@ SecurityFilter = wireActor[SecurityFilterActor]("filter").taggedWith[SecurityFilter]

class UserFinderActor(databaseAccess: ActorRef @@ DatabaseAccess, securityFilter: ActorRef @@ SecurityFilter) extends Actor {...}

val userFinder = wireActor[UserFinderActor]

It is also possible to wire an actor using a factory function. For that, the module provides three additional macros wireAnonymousActorWith, wireActorWith and wirePropsWith. Their usage is similar to wireWith (see Factory methods). For example:

class UserFinderActor(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter) extends Actor { ... }

object UserFinderActor {
  def get(databaseAccess: DatabaseAccess) = new UserFinderActor(databaseAccess, new SimpleSecurityFilter())
}

val theUserFinder = wireActorWith(UserFinderActor.get _)("userFinder")

Installation, using with SBT

The jars are deployed to Sonatype's OSS repository. To use MacWire in your project, add a dependency:

libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.5.9" % "provided"

libraryDependencies += "com.softwaremill.macwire" %% "macrosakka" % "2.5.9" % "provided"

libraryDependencies += "com.softwaremill.macwire" %% "util" % "2.5.9"

libraryDependencies += "com.softwaremill.macwire" %% "proxy" % "2.5.9"

MacWire is available for Scala 2.12, 2.13, 3 on the JVM and JS.

The macros subproject contains only code which is used at compile-time, hence the provided scope.

The util subproject contains tagging, Wired and the @Module annotation; if you don't use these features, you don't need to include this dependency.

The proxy subproject contains interceptors and scopes, and has a dependency on javassist.

Older 1.x release for Scala 2.10 and 2.11:

libraryDependencies += "com.softwaremill.macwire" %% "macros" % "1.0.7"

libraryDependencies += "com.softwaremill.macwire" %% "runtime" % "1.0.7"

Debugging

To print debugging information on what MacWire does when looking for values, and what code is generated, set the macwire.debug system property. E.g. with SBT, just add a System.setProperty("macwire.debug", "") line to your build file.

Scala.js

Macwire also works with Scala.js. For an example, see here: Macwire+Scala.js example.

Future development - vote!

Take a look at the available issues. If you'd like to see one developed please vote on it. Or maybe you'll attempt to create a pull request?

Migrating from 1.x

  • changed how code is split across modules. You'll need to depend on util to get tagging & Wired, and proxy to get interceptors and scopes
  • tagging moved to a separate package. If you use tagging, you'll need to import com.softwaremill.tagging._
  • removed wireImplicit
  • implicit parameters aren't handled by wire at all (they used to be subject to the same lookup procedure as normal parameters + implicit lookup)

Play 2.4.x

In Play 2.4.x, you can no longer use getControllerInstance in GlobalSettings for injection. Play has a new pattern for injecting controllers. You must extend ApplicationLoader, from there you can mix in your modules.

import controllers.{Application, Assets}
import play.api.ApplicationLoader.Context
import play.api._
import play.api.routing.Router
import router.Routes
import com.softwaremill.macwire._

class AppApplicationLoader extends ApplicationLoader {
  def load(context: Context) = {

    // make sure logging is configured
    Logger.configure(context.environment)

    (new BuiltInComponentsFromContext(context) with AppComponents).application
  }
}

trait AppComponents extends BuiltInComponents with AppModule {
  lazy val assets: Assets = wire[Assets]
  lazy val prefix: String = "/"
  lazy val router: Router = wire[Routes]
}

trait AppModule {
  // Define your dependencies and controllers
  lazy val applicationController = wire[Application]
}

In application.conf, add the reference to the ApplicationLoader.

play.application.loader = "AppApplicationLoader"

For more information and to see the sample project, go to examples/play24

Reference Play docs for more information:

Play 2.5.x

For Play 2.5.x, you must do the same as for Play 2.4.x, except the Logger configuration.

import play.api.LoggerConfigurator
class AppApplicationLoader extends ApplicationLoader {
  def load(context: Context) = {

    LoggerConfigurator(context.environment.classLoader).foreach {
      _.configure(context.environment)
    }
    // ... do the same as for Play 2.4.x
  }
}

Scala3 support

The Scala 3 version is written to be compatible with Scala 2 where possible. Currently there are a few missing features:

For full list of incompatibilities take a look at tests/src/test/resources/test-cases and util-tests/src/test/resources/test-cases .

Commercial Support

We offer commercial support for MacWire and related technologies, as well as development services. Contact us to learn more about our offer!

Copyright

Copyright (C) 2013-2021 SoftwareMill https://softwaremill.com.

More Repositories

1

elasticmq

In-memory message queue with an Amazon SQS-compatible interface. Runs stand-alone or embedded.
Scala
2,379
star
2

sttp

The Scala HTTP client you always wanted!
Scala
1,418
star
3

tapir

Declarative, type-safe web endpoints library
Scala
1,294
star
4

quicklens

Modify deeply nested case class fields
Scala
810
star
5

magnolia

Easy, fast, transparent generic derivation of typeclass instances
Scala
745
star
6

bootzooka

Simple project to quickly start developing a Scala-based microservice or web application, without the need to write login, user registration etc.
Scala
695
star
7

codebrag

Your daily code review tool
Scala
651
star
8

akka-http-session

Web & mobile client-side akka-http sessions, with optional JWT support
Scala
440
star
9

it-cfp-list

List of Call For Papers for IT conferences
374
star
10

retry

because you should never give up, at least not on the first try
Scala
347
star
11

diffx

Pretty diffs for scala case classes
Scala
343
star
12

kmq

Kafka-based message queue
Scala
320
star
13

scala-clippy

Good advice for Scala compiler errors
Scala
315
star
14

ox

Safe direct style concurrency and resiliency for Scala on the JVM
Scala
305
star
15

supler

Rapid Form Development library. Use your favourite JS frontend & Scala backend frameworks.
Scala
286
star
16

jox

Fast and Scalable Channels in Java
Java
149
star
17

mqperf

Scala
143
star
18

scala-common

Tiny independent libraries with a single purpose, often a single class
Scala
120
star
19

slick-eventsourcing

Example for "Entry level event-sourcing" blog
Scala
118
star
20

lemon-dataset

Lemons quality control dataset
99
star
21

maven-badges

A node.js implementation of https://github.com/jirutka/maven-badges, originally created in ruby.
TypeScript
85
star
22

sbt-softwaremill

A sane set of default build settings
Scala
72
star
23

akka-vs-scalaz

Scala
63
star
24

recursion-training

Recursion schemes training examples and exercises
HTML
59
star
25

livestub

The HTTP server stub you always wanted!
Scala
51
star
26

scala-sql-compare

Scala
50
star
27

stringmask

A micro-library for macro-based case class field masking in .toString
Scala
48
star
28

scala-id-generator

Scala
48
star
29

confluent-playground

Java
44
star
30

odelay

delayed reactions
Scala
42
star
31

sttp-model

Simple Scala HTTP model
Scala
42
star
32

saft

Scala
41
star
33

akka-simple-cluster-k8s

Scala
39
star
34

softwaremill-common

SoftwareMill Common library
Java
37
star
35

sttp-openai

Scala
34
star
36

walk-that-type

A tool for evaluating TypeScript types step by step.
TypeScript
31
star
37

FoXAI

The open-source library for explainable AI. Generic and easy to integrate with PyTorch.
Python
30
star
38

neme-plugin

Scala compiler plugin for turning non exhaustive match warnings into errors
Scala
29
star
39

scala-pre-commit-hooks

Pre-commit/Pre-push hooks for Scala
Python
29
star
40

zio2-structure

Scala
26
star
41

helisa

Scala API for jenetics
Scala
26
star
42

reactive-event-sourcing-java

Java
26
star
43

streams-tests

Scala
25
star
44

tapir-loom

Scala
24
star
45

free-tagless-compare

Free monads compared to tagless final
Scala
22
star
46

node-typescript-starter

A basic boilerplate for node + TypeScript development with debugger source maps support.
TypeScript
22
star
47

akka-http-session-faq

Java
21
star
48

sttp-apispec

OpenAPI, AsyncAPI and JSON Schema Scala models.
Scala
21
star
49

activator-reactive-kafka-scala

Activator template for Reactive Kafka
Scala
20
star
50

scala3-macro-debug

Scala
17
star
51

reactive-streams-for-java-developers

Java
17
star
52

resilience4s

Scala
16
star
53

react-use-promise-matcher

React hooks allowing you to handle promises in a stateful way
TypeScript
16
star
54

adopt-tapir

A quickstart generator for Tapir projects
Scala
15
star
55

simple-http-server

Simple JVM based HTTP server with no dependencies
Scala
15
star
56

correlator

Scala
15
star
57

detectnet-tests

Python scripts and other resources for tesing DetectNet on Nvidia DIGITS
Python
14
star
58

blockchain-schedule

An experimental collaborative planning app based on Ethereum ("Decentralized Doodle")
TypeScript
14
star
59

blog-scala-structure-lifecycle

Scala
12
star
60

akka-sandbox

Training ground for experiments with Akka framework.
Scala
12
star
61

broadway-pipelines-blog

Constructing effective data processing workflows using Elixir and Broadway
Elixir
12
star
62

undelay

Satisfy Scala Futures quickly
Scala
11
star
63

monix-correlation-id

Scala
10
star
64

cassandra-monitoring

Scripts for the Cassandra Monitoring blog miniseries
10
star
65

reason-companies-example

Reason example application
OCaml
10
star
66

jvmbot

Scala
9
star
67

meerkat

Bootzooka, but for observability
JavaScript
9
star
68

botarium

A simple starter kit for building bots using Node + TypeScript + BotKit.
TypeScript
8
star
69

sbt-template

Scala
8
star
70

asamal

POC for a CDI-based web lightweight framework
Java
8
star
71

boot-scala-microservice

Bootstrap microservice template that uses micro-deps library https://github.com/4finance/micro-deps
Scala
8
star
72

sttp-shared

Scala
7
star
73

modem-connector

Modulator and Demodulator for HAM Radio AX.25 audio signals
Scala
7
star
74

gatling-zeromq

A Gatling stress test plugin for ZeroMQ protocol
Scala
5
star
75

trqbox-demo

Ruby
5
star
76

idea-pastie-plugin

Plugin to post pastie.org pasties from IntelliJ Idea
Java
5
star
77

sentinel-cgan

Sentinel generative conditional adversarial network implementation
Python
5
star
78

scalatimes

Pug
5
star
79

scala-compiler-plugin-template

Scala
5
star
80

tapir-serverless

Scala
5
star
81

OtterJet

Java
5
star
82

slack-alphabet

Scala
4
star
83

scalar-conf-website

Scalar - Scala Conference in Central Europe
Python
4
star
84

try-them-off

Showcase service presenting possible usage of the Try monad from Vavr.
Java
4
star
85

sttp-openapi-example

Scala
4
star
86

cache-get-or-create

Java
4
star
87

bootzooka-react

Simple project to quickly start developing a web application using React and Akka HTTP, without the need to write login, user registration etc. https://softwaremill.com/open-source/
Scala
4
star
88

vehicle-routing-problem-java

Java
4
star
89

fabrica

Shell
3
star
90

akka-typed-workshop

Scala
3
star
91

kuberenetes-fundamentals

Training projects to explore k8s features
Scala
3
star
92

play-scala-slick-example-part2

Scala
3
star
93

ansible-bigbluebutton

Shell
3
star
94

kleisli-example

Scala
3
star
95

loom-protect

Java
3
star
96

supler-example

Example project for Supler http://supler.io
JavaScript
2
star
97

jekyll-softwaremill

SoftwareMill.com website written in Jekyll
PHP
2
star
98

demo-spring-boot-docker-compose

Demo application with comparison of spring-boot-docker-compose to testcontainers
Java
2
star
99

oauth_tutorial

Phoenix OAuth tutorial
Elixir
2
star
100

terraform-gke-bootstrap

HCL
2
star