<%= NewRelic::Agent.browser_timing_header rescue "" %>

David van Geest

Software, Life, and Stuff I Couldn't Find on the Internet

Dynamically getting a Scala companion object reference

| Comments

In my last post, I talked about dynamically getting a list of concrete subclasses in Scala. Now suppose that for each of those subclasses (with type Class[T]), I need a reference to its companion object.

This time, the standard Scala reflection API did exactly what I needed. The below code takes my list of subclasses, gets a reference to the companion object of each one, and then maps the result of a method on that companion object to the subclass itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
object Attribute {
  // find concreteAttributeClasses up here

  import scala.reflect.runtime.universe

  private val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)

  implicit val NameClassMap: Map[String, Class[_ <: Attribute[_]]] = (concreteAttributeClasses map { klass =>
    val module = runtimeMirror.staticModule(klass.getName)
    val companionObj = runtimeMirror.reflectModule(module).instance.asInstanceOf[OrgNamed]
    companionObj.orgName -> klass
  }).toMap
}

All of the companion objects must inherit the OrgNamed trait, so I can safely cast them and call orgName on each one.

Why these reflection gymnastics? The resulting NameClassMap allowed me to take arbitrary incoming network messages which had an orgName matching the keys in my map, and dynamically instantiate an appropriate Attribute instance for them. Here’s the code to do that:

1
2
3
4
5
6
7
8
9
10
11
12
13
object Attribute {
  // construct implicit NameClassMap up here

  def newFromName(name: String, value: String)
                 (implicit nameClassMap: Map[String, Class[_ <: Attribute[_]]]): Attribute[_] = {
    nameClassMap.get(name) match {
      case Some(klass) =>
        klass.getDeclaredConstructor(classOf[String]).newInstance(value)
      case None =>
        UnknownAttribute(name, value)
    }
  }
}

The magic, of course, is the dynamic instantiation provided by getDeclaredConstructor and newInstance.

I should note that aspects of this decrease the type safety of your code, and should really be used sparingly. In this particular case, the benefits outweighed the risks!

Finding concrete subtypes in Scala

| Comments

On my current project, which is written in Scala, I needed a way to dynamically find all of the concrete subclasses of a given class, found in a given package.

While this is possible using the Scala Reflection API, this bug did not give me confidence that it would work correctly. Instead, I turned to the library mentioned in the comments, namely Reflections, which is written in Java and can be found here.

Using this library made the task quite straightforward. In the code below, I’m finding all concrete subclasses of Attribute[_] found in the com.example package.

1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.reflect.Modifier
import org.reflections.Reflections

object Attribute {
  private val reflections = new Reflections("com.example")
  private val allAttributeClasses = reflections.getSubTypesOf(classOf[Attribute[_]])
  private val concreteAttributeClasses = allAttributeClasses filter { klass =>
    !Modifier.isAbstract(klass.getModifiers)
  }

  // do some useful stuff with the list of subclasses
}

Note that I’m making use of the standard Java reflection API to check whether a class is concrete or not.

In my next post I’ll talk about doing some interesting things with this list of subclasses!

Removing newlines from Logging events

| Comments

I added the Logging gem to a project I’m working on, and so far I like it a lot. It is modelled after log4j and, as such, allows you to send logs to syslog (our main usage for it).

One issue that I’ve run into with using syslog(-ng) as a Rails logger is that Rails tends to spit out multi-line log events. Unless you have a very new version of syslog-ng, this may cause syslog to interpret each new line as a new event. Unfortunately subsequent lines get written with a blank program identification, which can cause filtering rules in syslog-ng to break.

My solution to this was to monkeypatch the Logging::LogEvent with an Around Alias. This causes the data accessor to return a string with the newlines substituted with a different delimiter, << in this case. I added the Around Alias to the end of the config/logging.rb file:

config/logging.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Other config here...

# This is a hack to remove new lines from our log data
module Logging
  class LogEvent

    def data_with_stripped_newlines
      self.data_without_stripped_newlines.gsub("\n", " >> ")
    end

    alias_method_chain :data, :stripped_newlines

  end
end

So far it’s working quite nicely. Any better ways of doing it? Let me know!