Constructors vs Static Factory Method

I have wondered if this topic was relevant. I have often seen both ways to create an object. Why bother choosing between a static factory method and a constructor? It seemed to me that they do more or less the same, and the advantages of the static factor method were not so obvious. Why not using the constructor to do what it was invented for: constructing objects?! The choice did and still does feel a bit artsy (=preference). But let me list a few pros for the static method, and you may change your mind.

Advantage #1: name it!

How the heck is this more advantageous? Well, clarity. You can name your static method in a way that means what it is doing. For example, if you want to build a new garden, you can write:

Salad salad = Salad.from(lettuce);

instead of

Salad garden = new Salad(lettuce);

Hmm?? Was it better? Ok, fine. Not that much. But if you need arguments to create your object, you may have factor methods with different names. It can be particularly useful when the parameters are of the same type. For example, I want to make a salad:

public Salad(Green lettuce, Green spinach) {
// do something
}

Now if I want to make a salad with a different mix of green assuming it requires a different behavior, it will look like:

public Salad(Green lettuce, Green roman) {
// do something else
}

The signature is the same. Of course, we could figure out something else. If we have static methods, it will look more elegant:

Salad salad = Garden.makeDarkGreenMix(lettuce, spinach);
Salad salad = Garden.makeLightGreenMix(lettuce, roman);

Well, this example was not very elegant…

Advantage #2: save resources!

A static factory method does not have to create an object. The common example is the getInstance() method Java developers often use to create Singletons.

public static SaladChef getInstance() {
  if (chef == null) { // chef = private SaladChef property
    chef = new SaladChef();
  }
  return chef;
}

Another example would be a pool of connections. etc. It might help to avoid using resources.

Advantage #3: return a subclass!

A static method can return a subclass, but not the constructor. It may help to manage the types of objects return depending on the parameters.

public static Macbook buy(double amount) {
  if (amount < 1000) {
    return new MackbookAir();
  } else {
    return new MacbookPro();
  }
}

But there are two cons: classes without public or protected constructors cannot be inherited, and static factory methods are harder to find than constructors.

Honestly, I still question the systematic use of static factory methods. It is a nice way to code, but it must be used with caution. And I think it is still a matter of art.

Mockk framework: Could not initialize class io.mockk.impl.JvmMockKGateway

If you are looking for a mock framework for Kotlin tests, Mockk is definitely on first on the list. I wrote my first test following a simple example on the official website (https://mockk.io/#dsl-examples). In my case, I am testing an export class using a parser to deserialize a file into an object:

@Test
fun `test export excluding sub-folders`() {
    // given
    val path = "my/new/path"
    val parser = mockk()
    every { parser.buildObject("$path/data.xml") } returns MyObject("first name", "last name", "title", "manager")

    // when
    var myObject = exporter.parse(
            parser,
            getResourceFile(path),
            mutableListOf()
        )

    // then
    verify { parser.buildObject("$path/data.xml") }
    confirmVerified(parser) // verifies all the verify calls were made
    assertEquals("first name", myObject.firstName)
    assertEquals("last name", myObject.lastName)
    assertEquals("title", myObject.title)
    assertEquals("manager", myObject.manager)

}

Wunderbar! I ran my test… and it failed:

java.lang.NoClassDefFoundError: Could not initialize class io.mockk.impl.JvmMockKGateway

What in the world is that?! I checked my pom file and verified I had the latest version:

<dependency>
  <groupId>io.mockk</groupId>
  <artifactId>mockk</artifactId>
  <version>1.9.3</version>
  <scope>test</scope>
</dependency>

After a while, I figured out the issue resides in the IDE (https://github.com/mockk/mockk/issues/254). Mockk has issue when running on JDK 11. I went to Intellij IDEA -> File -> Project Structure, and changed the Project SDK to JDK 8 (which I use for my current project). You can probably find another version that would work for your own project.

Browsing folders with Kotlin

Kotlin offers significant improvements to Java. But coming from a Java background, it can sometimes get tricky. I was looking at browsing folders and I found Kotlin’s method walkTopDown:

fun File.walkTopDown(): FileTreeWalk

I used it recursively to find pom.xml files.

fun findPomFiles(
        folder: File,
        pomTrees: MutableList,
        includeDependencyManagement: Boolean,
        searchSubFolders: Boolean
    ): MutableList {

        // find pom file in the current folder
        val pomFile = folder.listFiles().find { it.name == "pom.xml" }

        pomFile?.let {
            println("Found pom file in $folder")
            pomTrees.add(PomNode(pomParser.deserialize(it), includeDependencyManagement))
        }

        if (searchSubFolders) {
            folder.walkTopDown() // HERE IS THE METHOD
                .filter { it.isDirectory && it != folder && it.name != "target" && it.name != "src"} // ignore src and target folders for performance
                .forEach {
                    findPomFiles(it, pomTrees, includeDependencyManagement, searchSubFolders)
                }
        }

        return pomTrees
    }

I also found the function onEnter of FileTreeWalk that can be used to avoid exploring useless branches.

fun onEnter(function: (File) -> Boolean): FileTreeWalk

folder.walkTopDown() // HERE IS THE METHOD
    .onEnter { it.name != "target" && it.name != "src"}

However, the result was not what I expected. The program was looking at the folders multiple times. I realize walkTopDown is not made for exploring folders recursively.
What it actually does is to browse folders and for each folder, we can do whatever we need to.

So two possibilities:

A. keeping the code recursive and using listFiles() from File – like we used to do it in Java

    if (searchSubFolders) {
        folder.listFiles()
            .filter { it.isDirectory && it != folder && it.name != "target" && it.name != "src"} // ignore src and target folders for performance
            .forEach {
                findPomFiles(it, pomTrees, includeDependencyManagement, searchSubFolders)
            }
    }

B. using walkTopDown

fun findPomFiles(
        folder: File,
        pomTrees: MutableList,
        includeDependencyManagement: Boolean,
        searchSubFolders: Boolean
    ): MutableList {

        // find pom file in the current folder
        addPomNode(folder, includeDependencyManagement)?.let { pomTrees.add(it) }

        if (searchSubFolders) {
            folder.walkTopDown()
                .onEnter { it.name != "target" && it.name != "src" }
                .forEach {
                    addPomNode(it, includeDependencyManagement)?.let { pomNode -> pomTrees.add(pomNode) }
                }
        }

        return pomTrees
    }

    fun addPomNode(folder: File, includeDependencyManagement: Boolean): PomNode? {
        val pomFile = folder.listFiles()?.find { it.name == "pom.xml" }

        pomFile?.let {
            println("Found pom file in $folder")
            return PomNode(pomParser.deserialize(it), includeDependencyManagement)
        }

        return null
    }