How could I convert the following into scala.
public class JedisDB {
private static final JedisPool jedisPool = new JedisPool(getJedisPoolConfig());
public static JedisPoolConfig getJedisPool() {
// ..
}
public int getTest123() {
jedisPool.getResource();
// code goes here
}
}
I have seen answers do create a class and a companion object, but can someone explain to me exactly how and why I should do this?
Should I create what I want to expose as a static variable in the companion object, and the loading of the configuration file that is used to initialize the jedisPool in the class?
Do I have the option of making jedisPool public or private in the companion object?
Also (not to effect the answer to my question but as a added benefit), I read somewhere but didn't fully understand that this makes pattern makes testing difficult, are there workarounds then?
lazy val jedisPool : JedisPool = {
val poolConfig = createPoolConfig(app)
new JedisPool(poolConfig)
}
To get a resource
val j = jedisPool.getResource()
make sure you return resource after done using it.
jedisPool.returnResource(j)
Basically it does not metter if static methods will go to companion object or any other object. A companion object differs from other objects as it has access rights to the class/trait that other objects do not. But that's not really your's example.
Your sample with companion object:
// -- helpers to be able compile
class JedisPoolConfig { }
class JedisPool(p: JedisPoolConfig) {
def getResource = 1
}
// --
// everythis that should be SINGLETON goes into object
object JedisDB {
private lazy val jedisPool = new JedisPool(getJedisPool)
def getJedisPool = new JedisPoolConfig() // or any other implementation
def otherStaticMethod = new JedisDB().anyVal // wow - got access to private val.
}
class JedisDB {
import JedisDB._
def getTest123() = jedisPool.getResource
private val anyVal = "SomeValue";
// other methods
}
// other - non companion object
object JedisDB2 {
// def otherStaticMethod = new JedisDB().anyVal // no luck - no access
}
Related
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.
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.
I have a Controller with a constructor where I´m injecting a cache, but also I would like to invoke a method in the constructor when the instance is created. I know we can create some auxiliary constructors with
def this(foo:Foo){}
But in my case because is play framework the one that instance my bootstrap is a little bit more complex.
Here my code
class SteamController #Inject()(cache: CacheApi) extends BaseController {
private val GAME_IDS_LIST_API: String = "api.steampowered.com/ISteamApps/GetAppList/v2"
private val GAME_API: String = "store.steampowered.com/api/appdetails?appids="
private val GAME_KEY: String = "games"
def games = Action { implicit request =>
var fromRequest = request.getQueryString("from")
if (fromRequest.isEmpty) {
fromRequest = Option("0")
}
val from = Integer.parseInt(fromRequest.get) * 10
val to = from + 10
loadGameIds()
Ok(html.games(SteamStore.gamesIds(cache.getVal[JSONArray](GAME_KEY), from, to), cache.jsonArraySize(GAME_KEY)/10))
}
private def loadGameIds(): Unit = {
val games = cache.get(GAME_KEY)
if (games.isEmpty) {
get(s"$GAME_IDS_LIST_API", asJsonGamesId)
cache.set(GAME_KEY, lastResponse.get, 60.minutes)
}
}
What I would like is that loadGameIds would be invoked and cached when the class is instantiated.
Any suggestion?
Regards.
If I understand correctly your question, you simply want to add some statements to the main constructor body? If that's the case, you can simply do so in the body of the class itself. In your case, that would look like this:
class SteamController #Inject()(cache: CacheApi) extends BaseController {
...
private val GAME_KEY: String = "games"
loadGameIds() // <-- Here we are calling from the main constructor body
def games = Action { implicit request =>
...
}
...
}
When doing so, it is usually a good idea to perform additional code after the declaration of all vals and vars in your class, to ensure they are properly initialized at the time your additional constructor code runs.
I have the following class setup:
class MyClass {
class MyInnerClass(memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
Then I have the following code outside of the class:
def myFunction = {
val a = new MyClass
val b = a.getAInner.memberVar // value memberVar is not a member of a.MyInnerClass
}
Why is this?
You need to add the keyword val to make memberVar public otherwise it's a private value:
class MyClass {
class MyInnerClass(val memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
#Noah's answer is totally correct, but I would also throw out the option of using case class. See here for some of the sugar it provides. I use it almost reflexively. In your example, it would be:
object MyClass {
case class MyInnerClass(memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
def myFunction = {
val b = MyClass.getAInner.memberVar
}
I tend to do it this way because invariably, I want to take advantage of the sane defaults case class provides.
I also chose to use object for the outer type, because it doesn't have any parameters, although you may have just done that for simplicity's sake.
Could someone explain why scala would allow a public variable, to satisfy the implementation of an abstract declared Protected item? My first assumption is that the compiler would complain, but I created a small test to see if this worked, and to my surprise it does. Is there an advantage to this? (perhaps this is normal in OOP?) Any methods to avoid the accidental pitfall?
object NameConflict extends App {
abstract class A {
protected[this] var name:String
def speak = println(name)
}
class B(var name:String) extends A { //notice we've declared a public var
}
val t = new B("Tim")
t.speak
println(t.name) // name is exposed now?
}
It's normal and as in Java. Sometimes it's desirable to increase the visibility of a member.
You can't do it the other way around and turn down visibility in a subclass, because the member can by definition be accessed through the supertype.
If invoking a method has terrible consequences, keep the method private and use a template method that can be overridden; the default implementation would invoke the dangerous method.
abstract class A {
private[this] def dangerous = ???
final protected def process: Int = {
dangerous
template
}
protected def template: Int = ???
}
class B extends A {
override def template = 5
}