How would you wrap a class containing a concurrenthash map with cats? - scala

Say I have a class that contains an inner concurent hash map
final class SomeClass() {
private val byUserId = new ConcurrentHashMap[User.ID, Vector[User]](64)
// ...
}
Now if I wanted to have this class referenced in my API endpoints and other areas in my services, how would I wrap this in a cats IO/effects?
Since this is already management state, would it still be an effects IO?
Need some guidance on this as I am a little confused and newish to FP.

I guess it depends on how you are going to use it. Here are my thoughts on this.
So you probably want one instance of this class (and one map) shared between different processes, right? So the instantiation of it should be wrapped in IO. Then you can inject it as a dependency in all other places where you need to use it. Then all the public methods of this class that have anything to do with the Map should return an IO as well.
final class SomeClass private() {
private val byUserId = new ConcurrentHashMap[User.ID, Vector[User]](64)
def getById(id: User.ID): IO[Vector[User]] = ???
def setUser(id: User.ID, user: Vector[User]): IO[Unit] = ???
}
object SomeClass {
def apply() = IO(new SomeClass())
}
SomeClass().flatMap { instance =>
// do stuff with it
Api(instance)
}

Related

How do I mock a Scala Companion Object with EASYMOCK on Scala 3? [duplicate]

This question already has an answer here:
How to mock an Object in Scala
(1 answer)
Closed 7 months ago.
I have the following code...
class CoreDataSource {
def getConnection = {
println("Getting the connection")
CoreDataSource.getConnection
}
}
object CoreDataSource {
def getConnection: Option[Connection] = {
getDataSource.get.getConnection
}
def getDataSource: Option[DataSource] = {
...
config = new HikariConfig // This has side effects and can't run
...
val pool : DataSource = new HikariDataSource(config) // This has side effects and can't run
...
Some(pool)
}
}
I am trying to mock out the creation of the HikariDataSource and HikariConfig. I tried this...
class CoreDataSourceSpec extends AnyFunSpec with EasyMockSugar {
describe("Core Data Source") {
it("Do something") {
val cdsMock = mock[CoreDataSource.type]
...
}
}
}
But I get
Cannot subclass final class ....CoreDataSource$
What is the proper way to Mock out a companion object using EasyMock
You don't.
Companion object should only perform pure computations (at least don't contain state) which don't require mocking. Most of the time it's purpose is to store factories and instances of type classes (implicits/givens) for your type.
If you store a mutable state (e.g. connection to the database) in companion you messed up. If you have a Java background, think this way: would you mock static methods of a class? (If you're drifting towards PowerMockito you should reconsider your life choices).
Your example shows that you want to store the connection somewhere - storing it in companion is basically global, shared, mutable state which is universally a bad idea, no matter the background.
Create factory of CoreDataSource in its companion, then pass around CoreDataSource instance directly. No issue with mocking that in your tests.
class CoreDataSource(dataSource: DataSource) {
def getConnection: Connection =
dataSource.getConnection
}
object CoreDataSource {
def createHikari(config: HikariConfig): CoreDataSource =
new CoreDataSource(new HikariDataSource(config))
}
// in test:
val dataSource = mock[DataSource]
val coreDataSource = new CoreDataSource(dataSource)
// then mock dataSource.getConnection
Doing it another way requires solving the hard problem that you have 0 reasons to have in the first place. If this companion object is not your but someone else and you cannot rewrite it - wrap it in your own code that you can control and mock easily.
EDIT. In case you are using something like Google Cloud... it still doesn't make sense to store everything in companion and mock it.
// functionality
class MyService(
connection: Connection
) {
def someFunctionality(arg: Arg): Result = ...
}
// in test
// given
val connection = mock[Connection] // mocking DB sounds like a bad idea but whatever
val myService = new MyService(connection)
// when
myService.someFunctionality(arg)
// then
// assertions
// adapter for Google Cloud, other cloud solutions should be similar
class MyFunction extends HttpFunction {
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
private val myService = new MyService(connection)
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = myService.someFunctionality(arg)
// then send result in response
}
}
And if you needed to cache these private vals - what you are caching is NOT related to business logic at all, it merely wires things together, like main in Java which is never tested, nor require testing.
So you could implement it like:
class MyFunction extends HttpFunction {
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = MyFunction.myService.someFunctionality(arg)
// then send result in response
}
}
object MyFunction {
// dependency injection and initialization
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
val myService = new MyService(connection)
}
where wrapper MyFunction is NOT tested, but MyService which does all the job is easily testable.
You should definitely read more about the language, beside the fact that the other answer mentioned (which is you should only contain pure class-level functionalities in the companion object), you cannot do it. Why? Because companion objects are singleton objects of a final class, which can access private states of the companion class itself and vice versa (think of it kind of like static data of the class).
The thing is, companion object actually is an object of a final class (which if you want, I can provide more details about them). Final classes cannot be mocked, simply because they are "final", and their behavior cannot be changed (even by its subclasses). And mocking is all about mocking a class behavior, not an object's behavior.

How to provide scala object's with classes that have dependancy injection?

I have a different car object's, one for example:
object Porsche extends Car with CarsUtilities {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
this is how Car and CarsUtilities looks like:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
trait CarsUtilities {
// method to prepare start() result
def prepareResult() = {...}
}
I have two api services:
class CarApiService (wsClient: WSClient, configuration: Configuration) {
def getCarkey(carId: String): Future[Option[CarKey]] = {
// here im performing api call using wsclient
}
}
and
class CarSupplierApiService #Inject()(configuration: Configuration) {
def getSupplierInfo(carId: String): Future[Option[SupplierInfo]] = // here im performing elastic search api call
}
Now, In some of the car object's, lets say 50% of them im gonna use those api services, sometime both and other times just one of them. What would be a best practice of providing those car objects those services instances?
I dont really want to use new to create an instance of them for each object that need to use them...so I thought maybe add them lazily to the CarsUtilities so all the car objects will have access to those api services when they need them...would that be a good solution?
also, if I do that how do I give then the Configuration and WSClient injections?
trait CarsUtilities {
lazy val carApiService = new CarApiService(???)
lazy val carSupplierApiService = new CarSupplierApiService(???)
// method to prepare start() result
def prepareResult() = {...}
}
thanks!!
using playframework 2.6, scala 2.11.8 :)
Generally, dependency injection and objects doesn't work together. Please see here for work-arounds, but in the long term you wan to get rid of objects that depend on injected classes.
What you probably need is some sort of business service that is a class an may be injected in controllers, like so:
class CarsUtilities #Inject() (carApiService: CarApiService, carSupplierApiService: CarSupplierApiService) {
// this class implements all the business logic and can use the services
def prepareResult() = {}
}
In the controllers, you may inject this CarsUtilities as well, because dependency injection "propagates".

Injecting playFramework dependancies to scala object using MacWire traits fail

Lets say I have bunch of car objects in my project, for example:
object Porsche extends Car {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
im extending Car which is just a trait to set a car structure:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
Now, in the start() method I want to use some api service that will give me a car key based on its id so I cant start the car.
So I have this CarApiService:
class CarApiService (wsClient: WSClient, configuration: Configuration) {
implicit val formats: Formats = DefaultFormats
def getCarkey(carId: String): Future[Option[CarKey]] = {
val carInfoServiceApi = s"${configuration.get[String]("carsdb.carsInfo")}?carId=$carId"
wsClient.url(carInfoServiceApi).withHttpHeaders(("Content-Type", "application/json")).get.map { response =>
response.status match {
case Status.OK => Some(parse(response.body).extract[CarKey])
case Status.NO_CONTENT => None
case _ => throw new Exception(s"carsdb failed to perform operation with status: ${response.status}, and body: ${response.body}")
}
}
}
}
I want to have the ability to use getCarkey() in my car objects, so I created a CarsApiServicesModule which will give my access to the carApiService and I can use its methods:
trait CarsApiServicesModule {
/// this supply the carApiService its confuguration dependancy
lazy val configuration: Config = ConfigFactory.load()
lazy val conf: Configuration = wire[Configuration]
/// this supply the carApiService its WSClient dependancy
lazy val wsc: WSClient = wire[WSClient]
lazy val carApiService: CarApiService = wire[CarApiService]
}
and now I want to add mix this trait in my car object this way:
object Porsche extends Car with CarsApiServicesModule {
// here I want to use myApiService
// for example: carApiService.getCarkey(carId)...
}
but when compiling this I get this error:
does anyone know what is the issue?
also, is that design make sense?
You need to keep in mind that wire is just a helper macro which tries to generate new instance creation code: it's quite dumb, in fact. Here, it would try to create a new instance of WSClient.
However, not all objects can be instantiated using a simple new call - sometimes you need to invoke "factory" method.
In this case, if you take a look at the readme on GitHub, you'll see that to instantiate the WSClient, you need to create it through the StandaloneAhcWSClient() object.
So in this case, wire won't help you - you'll need to simply write the initialisation code by hand. Luckily it's not too large.

Chain functions in different way

Scala functions has following methods for chaining:
fn1.andThen(fn2)
fn1.compose(fn2)
But how can be written this case:
I have function cleanUp() which has to be called always as last step.
And I have a bunch of other functions, like that:
class Helper {
private[this] val umsHelper = new UmsHelper()
private[this] val user = umsHelper.createUser()
def cleanUp = ... // delete user/ and other entities
def prepareModel(model: TestModel) = {
// create model on behalf of the user
}
def commitModel() = {
// commit model on behalf of the user
}
}
And some external code can use code something like this:
val help = new Helper()
help.prepareModel()
help.commitModel()
// last step should be called implicitly cleanUp
How this can be written in a functional way, that chaining will always
call cleanUp function implicitly as last step?
Note: I see it as analogue of destructor in C++. Some chaining (doesn't matter how this chain is done) fn1 andLater fn2 andLater fn3 have to call as last step cleanUp (fn1 andLater fn2 andLater fn3 andLater cleanUp). Wrong with directly writing cleanUp method is there is a big chance someone will miss this step and user will be leaked (will be stayed in database)
This is a more advanced alternative:
When you hear "context" and "steps", there's a functional pattern that directly comes to mind: Monads. Rolling up your own monad instance can simplify the user-side of putting valid steps together, while providing warranties that the context will be cleaned up after them.
Here, we are going to develop a "CleanableContext" construction that follows that pattern.
We base our construct on the most simple monad, one whose only function is to hold a value. We're going to call that Context
trait Context[A] { self =>
def flatMap[B](f:A => Context[B]): Context[B] = f(value)
def map[B](f:A => B): Context[B] = flatMap(f andThen ((b:B) => Context(b)))
def value: A
}
object Context {
def apply[T](x:T): Context[T] = new Context[T] { val value = x }
}
Then we have a CleanableContext, which is capable of "cleaning up after itself" provided some 'cleanup' function:
trait CleanableContext[A] extends Context[A] {
override def flatMap[B](f:A => Context[B]): Context[B] = {
val res = super.flatMap(f)
cleanup
res
}
def cleanup: Unit
}
And now, we have an object that's able to produce a cleanable UserContext that will take care of managing the creation and destruction of users.
object UserContext {
def apply(x:UserManager): CleanableContext[User] = new CleanableContext[User] {
val value = x.createUser
def cleanup = x.deleteUser(value)
}
}
Let's say that we have also our model and business functions already defined:
trait Model
trait TestModel extends Model
trait ValidatedModel extends Model
trait OpResult
object Ops {
def prepareModel(user: User, model: TestModel): Model = new Model {}
def validateModel(model: Model): ValidatedModel = new ValidatedModel {}
def commitModel(user: User, vmodel: ValidatedModel): OpResult = new OpResult {}
}
Usage
With that reusable machinery in place, our users can express our process in a succinct way:
import Ops._
val ctxResult = for {
user <- UserContext(new UserManager{})
validatedModel <- Context(Ops.prepareModel(user, testModel)).map(Ops.validateModel)
commitResult <- Context(commitModel(user, validatedModel))
} yield commitResult
The result of the process is still encapsulated, and can be taken "out" from the Context with the value method:
val result = ctxResult.value
Notice that we need to encapsulate the business operations into a Context to be used in this monadic composition. Note as well that we don't need to manually create nor cleanup the user used for the operations. That's taken care of for us.
Furthermore, if we needed more than one kind of managed resource, this method could be used to take care of managing additional resources by composing different contexts together.
With this, I just want to provide another angle to the problem. The plumbing is more complex, but it creates a solid ground for users to create safe processes through composition.
I think that the core of the question is "how to keep a resource within a managed context". i.e. provide users with a way to use the resource and prevent it to 'leak' outside its context.
One possible approach is to provide a functional access to the managed resource, where the API requires functions to operate over the resource in question. Let me illustrate this with an example:
First, we define the domain of our model: (I've added some subtypes of Model to make the example more clear)
trait User
trait Model
trait TestModel extends Model
trait ValidatedModel extends Model
trait OpResult
// Some external resource provider
trait Ums {
def createUser: User
def deleteUser(user: User)
}
Then we create a class to hold our specific context.
class Context {
private val ums = new Ums{
def createUser = new User{}
def deleteUser(user: User) = ???
}
def withUserDo[T](ops: User => T):T = {
val user = ums.createUser
val result = ops(user)
ums.deleteUser(user)
result
}
}
The companion object provides (some) operations on the managed resource. Users can provide their own functions as well.
object Context {
def prepareModel(model: TestModel): User => Model = ???
val validateModel: Model => ValidatedModel = ???
val commitModel: ValidatedModel => OpResult = ???
}
We can instantiate our context and declare operations on it, using a classic declaration, like:
val ctx = new Context
val testModel = new TestModel{}
val result = ctx.withUserDo{ user =>
val preparedModel = prepareModel(testModel)(user)
val validatedModel = validateModel(preparedModel)
commitModel(validatedModel)
}
Or, given the desire in the question to use functional composition, we could rewrite this as:
val result = ctx.withUserDo{
prepareModel(testModel) andThen validateModel andThen commitModel
}
Use autoClean this will automatically call cleanUp at the end.
create a HelperStuff trait which contains all the necessary functions.
Inside the Helper object create a private implementation of the HelperStuff and then have a method method called autoClean which does the work keeping the Helper instance private and safe way from the rouge users.
Helper.autoClean { helperStuff =>
//write all your code here. clean up will happen automatically
helper.foo()
helper.commitModel()
}
Here is the autoClean function for you
trait HelperStuff {
def foo(): Unit
def commitModel: Unit
def cleanUp(): Unit
}
object Helper {
private class Helper extends HelperStuff {
def foo(): Unit = println("foo")
def cleanUp(): Unit = println("cleaning done")
}
private val helper = new Helper()
def autoClean[T](code: HelperStuff => T): T = {
val result = code(helper)
helper.cleanUp()
result
}
}

Abstract fields for dependency injection

In Scala, is there there anything wrong with using the below method of dependency injection.
// Define an interface
trait FileStorage {
def readFile(filename:String):OutputStream
}
// And an implementation
class S3FileStorage extends FileStorage {
def readFile(filename:String):OutputStream = ???
}
// Define our service as a trait with abstract fields that need to be
// injected in order to construct. All implementation details go here.
trait FileHTTPServer {
val fileStorage:FileStorage
def fetchFile( session:Session, filename:String ) = ???
}
Now we wire things up
// Wire up a concrete file service that we actually use in code
// No implementation details should go here, we're simply wiring up a FileHttpServerl
// An entire project could be wired up this way in a central location if desired.
object S3FileHttpServer extends FileHTTPServer {
val fileStorage = new S3FileStorage
}
// We could also do this anonymously
val myHttpServer = new FileHttpServer {
val fileStorage = new S3FileStorage
}
// Or create a mocked version for testing
val mockedHttpServer = new FileHttpServer {
val fileStorage = mock[FileStorage]
}
Obviously the Cake pattern provides more flexibility (particularly around self-types), however for simpler use cases this has much less boilerplate, while still providing compile time checking and a clean unambiguous interface.
Yes, this is absolutely fine approach. And yes, sometimes you can use constructor injection, nothing wrong with that too. But with constructor injection you have to propagate your dependencies manually, while with cake pattern your dependencies are propagated automatically via self-type annotations. So for big projects constructor injection actually lead to more boilerplate than cake pattern, especially at the construction site (where you create all your objects and set up dependencies between them).
However, what you have presented is not full-fledged cake pattern. In real cake pattern there is an additional layer around business logic classes, so-called components, and you do not wire up logic classes directly but components instead.
trait FileStorageComponent {
def fileStorage: FileStorage
trait FileStorage {
def readFile(filename: String): OutputStream
}
}
trait S3FileStorageComponent extends FileStorageComponent {
val fileStorage = new S3FileStorage
class S3FileStorage extends FileStorage {
def readFile(filename: String): OutputStream = ???
}
}
trait FileHttpServerComponent {
self: FileStorageComponent =>
val fileHttpServer = new FileHttpServer
class FileHttpServer {
def fetchFile(session: Session, filename: String) = ???
}
}
// Wiring
object S3FileHttpServer extends FileHttpServerComponent with S3FileStorageComponent
// Anonymous
val server = new FileHttpServerComponent with S3FileStorageComponent
// Mocking
object TestFileHttpServer extends FileHttpServerComponent with FileStorageComponent {
val fileStorage = mock[FileStorage]
}
In this approach there are more boilerplate in traits definitions, but in return you have greater flexibility and very clear dependency management on the use place. For example, here is how program entry point in one of my projects looks like:
object Main
extends MainUI
with DefaultActorsManagerComponent
with DefaultPreferencesAccessComponent
with DefaultModelComponent
with DefaultMainWindowViewComponent
with DefaultMainWindowControllerComponent
with MainWindowReporterComponent
with DefaultClientActorComponent
with DefaultResponseParserActorComponent
with DefaultArchiverActorComponent
with DefaultMainWindowAccessActorComponent
with DefaultUrlParserComponent
with DefaultListenerActorComponent
with DefaultXmlPrettifierComponent
All main program components are in one place. Pretty neat IMO.