How to call a function from a java library

Can someone help me figure out what I need to do to call the function getCollectionCount() from this java library?

What do I need to import, what do I need to add to my build.sbt etc?

This is what I’ve tried, but it doesn’t work.

import java.lang.management._
val beans: Array[GarbageCollectorMXBean] = ManagementFactory.getGarbageCollectorMXBeans().toArray

val gcCount0 = beans(0).getCollectionCount()
val gcTime0 = beans(0).getCollectionTime()
println(s"gcCount0=$gcCount0   gcTime0=$gcTime0")

Here is the message I get from IntelliJ
Screenshot 2020-03-05 at 09.06.57

And I get the following compiler error. Which I don’t understand. Do I really need to use a wildcard such as _ >: java.lang.management.GarbageCollectorMXBean from SLS 3.2.10

My feeling is that this 3.2.10 error is a red herring, that I’m simply not accessing the getCollectionCount and getCollectionTime methods correctly.

Error:(198, 99) type mismatch;
 found   : Array[Object]
 required: Array[java.lang.management.GarbageCollectorMXBean]
Note: Object >: java.lang.management.GarbageCollectorMXBean, but class Array is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: java.lang.management.GarbageCollectorMXBean`. (SLS 3.2.10)
        val beans: Array[GarbageCollectorMXBean] = ManagementFactory.getGarbageCollectorMXBeans().toArray

Your problem is actually with the java.util.List API. Its toArray method returns a Array[AnyRef].

You can use this other toArray method, which I find quite ridiculous to be honest:

ManagementFactory
  .getGarbageCollectorMXBeans()
  .toArray(Array.empty[GarbageCollectorMXBean])

Or you can move to the Scala universe where toArray does what one would expect:

import scala.jdk.CollectionConverters._

ManagementFactory
  .getGarbageCollectorMXBeans()
  .asScala
  .toArray

thanks. Is scala.jdk correct or a typo? My system doesn’t find it. Maybe I need to update my build.sbt file?

In Scala 2.13 that should work.
In older versions it’s scala.collection.JavaConverters.

So, here is the code I’m running. It seems to work, although I’m still analyzing the results.
As I’m not sure how many beans I will have (perhaps just 1), I’m folding over the results to add up all of them. That’s probably fine for the gc-count, but perhaps dubious for the time. Perhaps time should be maximized rather than summed???

import java.lang.management._

// Thanks Jasper M for the following recipe.
// https://users.scala-lang.org/u/jasper-m
// https://users.scala-lang.org/t/how-to-call-a-function-from-a-java-library/5722/2
val beans: Array[GarbageCollectorMXBean] = ManagementFactory
       .getGarbageCollectorMXBeans()
       .toArray(Array.empty[GarbageCollectorMXBean])

def gcCount(): Long = beans.foldLeft(0L) { (acc, b) => b.getCollectionCount() + acc }

def gcTime(): Long = beans.foldLeft(0L) { (acc, b) => b.getCollectionTime() + acc }

val gcCount0 = gcCount().toDouble
val gcTime0 = gcTime().toDouble
val (colorization, bdd) = graphToBdd(List(start), uniGraph, biGraph, numNodes,
                                     (n: Double, size: () => Double) => {
                                       newGcCount(n, gcCount() - gcCount0)
                                       newGcTime(n, gcTime() - gcTime0)
                                       newSize(n, size())
                                       val (hashSize, numAllocations) = Bdd.getBddSizeCount()
                                       newHashSize(n, hashSize.toDouble)
                                       newNumAllocations(n, numAllocations.toDouble)
                                     },
                                     differentColor,
                                     fold = fold)
     

I have 2. Probably one is for young generation and another one is for old generation. For information about objects’ generations look at https://en.wikipedia.org/wiki/Tracing_garbage_collection#Generational_GC_(ephemeral_GC)

Time should be summed if you want total time. In most GCs young and old GC cycles don’t overlap.

2 Likes