Dependency Injection on Class Instantiated Elsewhere - scala

I am trying to inject ehcache via the Play Framework. I am injecting it into a companion class, but that class is being instantiated in an abstract class elsewhere as well as the companion object. I do not want to inject anything into the abstract class because it is being used elsewhere.
For example, this is basically how the companion class and object are set up (removed some logic and extensions for better readability):
class Setting #Inject()(cached: DefaultSyncCacheApi) {
def isCached(id:String): Boolean = {
val cachedItem = cached.get(id)
cachedItem.isDefined
}
}
object Setting {
def getId(id:String): Setting = {
val setting = new Setting //I know this doesn't work
if (setting.isCached(id)) {
//retrieval logic
}
setting
}
}
This is the abstract class where it is being instantiated:
abstract class UsingSettingAbstract {
def methodUsingSetting(): String = {
val setting = new Setting
val str = new String
//logic in here
str
}
}
I have tried to create an empty constructor in the Setting class with def this() { }, and creating a chain of constructors, but have so far been unsuccessful in getting the cache to be successfully injected.
I did different versions of below, initializing the cache variable with cached or trying to pass through cached:
class Setting #Inject()(cached: DefaultSyncCacheApi) {
val cache:DefaultSyncCacheApi
def this() {
this(cache)
}
}
Is there a way to get DI to work with this setup, or would something like a factory pattern work better?

With guice you can pass any created instance to the injectors "requestInjection()" method. This will trigger method and field injection on that instance.
So as long as you have access to the injector, you can get injections done.

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 inject Scala classes in objects?

I want to use a singleton class in a Scala companion object but I am using Guice dependency injection and, as far as I know, it has no explicit usage in these scenarios.
As an example, let's say we have Singleton (using Guice) class as follows:
#Singleton
class Foo Inject()(foo2: Foo2) {
def func = { ... }
}
I can use it in other classes as:
class MyClass Inject()(foo: Foo) {
foo.func()
}
What about objects? I need to create an instance with new as:
object MyObject {
val foo2 = new Foo2()
val foo = new Foo(foo2)
foo.func()
}
In this case, does Foo still have just one instance? I mean, does new Foo(foo2) return the same instance as Guice returns in #Inject()(foo: Foo)?
By the way, there are already questions about this (e.g., link) but I want to use objects and access the singleton instances inside them.
In this case, does Foo still have just one instance? I mean, does new Foo(foo2) return the same instance as Guice returns in #Inject()(foo: Foo)?
No. Just as if you call new Foo(...) elsewhere. My suggestion would just be not to mix it; if you want to use Guice's instances inside MyObject, make it a Guice singleton class as well. Or make Foo an object, you can still access it from Guice-using classes.
If you really need it, the way I can think of is really ugly; to store the Injector from your main (or wherever you create it) somewhere MyObject can access it, i.e.
object Main {
var injector: Injector = null
def main(args: Array[String]): Unit = {
// make sure this happens before MyObject is accessed
injector = Guice.createInjector(...)
...
}
}
object MyObject {
val foo = Main.injector.getInstance(classOf[Foo])
foo.func()
}
If you don't even create the Injector yourself, but are using some framework which uses Guice, check if it gives you access to the Injector.

How to create mock object of a class which is package private

I have a class. It has a companion object A with a factory method.
class A private[somepackage](x: Int) {
}
object A {
def createA(y: Int): A = {
new A(y)
}
}
Now I need to create the mock object of A in a scalatest file which is in a different package.
When I give
private val a = mock[A] --> I get compilation error.
constructor A in class A cannot be accessed in <<somewhere>>.
Is there a better way to mock the object ??
In your test sources, create a test double in the same package:
package somepackage
class MockableA extends A(0)
then just create a mock[MockableA] in your tests and continue as usual.
But the answer with a proxy/facade should work too if you are willing to change production sources to facilitate tests.
Consider using a proxy to access class A, and stub/mock that proxy class instead.
E.g., if A.doStuff is what you want to mock/stub, and A.accessStuff is what you need in your code, create a class
class ADecorated(underlying: A) {
def doStuff() {
underlying.doStuff()
// whatever I want to do
}
def accessStuff() {
x = underlying.accessStuff()
// do something else and return
}
// Any other method you want to use
}
Replace usage of A.createA with new ADecorated(A.createA()). ADecorated is what you work with now

Scala: Extracting annotation from singleton object via reflection

How can one access the annotation of a singleton object given a string?
I am using Scala version 2.11.6 and plan to upgrade to 2.12 after sorting this issue out.
Example
Given an (java) annotation
public #interface Marked {
String name();
}
and a simplified factory interface
trait Instance { def doSomething(): Unit }
trait Factory { def create(): Instance }
I would like to check whether a dynamically loaded singleton object is annotated and with what value. The singleton object will be put in the classpath and may be defined as such:
class A extends Instance { override def doSomething() { println("A is done.") } }
#Marked(name = "My A Factory")
object AFactory extends Factory {
override def create(): Instance = new A()
}
What I tried
I can only access the module (singleton object) dynamically and in this way fail to access the annotation. Mostly due to lack of comprehensive documentation I have tried the following expressions which all somehow return an empty list.
import scala.reflect.runtime.{universe => ru}
val name = "AFactory$" // This is automatically provided.
val rm = ru.runtimeMirror(getClass.getClassLoader)
val classSym = rm.staticClass(name)
println(classSym.annotations)
println(classSym.companion.annotations)
println(classSym.baseClasses(0).annotations)
println(classSym.baseClasses(0).companion.annotations)
val moduleSym = rm.staticModule(name)
println(moduleSym.companion.annotations)
println(moduleSym.asModule.annotations)
println(moduleSym.asModule.moduleClass.annotations)
println(moduleSym.asModule.moduleClass.companion.annotations)
You need to make the JVM retain the annotation during runtime, otherwise it wont work =>
#Retention(RetentionPolicy.RUNTIME)
public #interface Marked {
}
With this change, your code worked.
Edit:
The reason is, that the default retention is "Class", which will make the compiler retain the annotaion in the classfile, but it wont be accessible during the runtime.

Initialize internal object just once

In Scala, I have the following class:
class A(param: String) {
object B {
lazy val db = {new D(param)}
}
}
and then from client code I have to create class A objects multiple times but have the B.db parameter be initialized just once. Currently, this does not work as it will create a new instance of object B every time and instance of class A is created.
To add a bit of perspective, the B.db object is an instance of the Mongo class, which according to the documentation needs to be initialized just once. How would you go about it?
put it in a companion object instead of an internal object
object A {
apply(param:String) {
new A
}
lazy val db = {..}
}
class A{
}