Skip to content

Scala Support

Tim Dalton edited this page Jan 5, 2021 · 8 revisions

Scala Support

Scala support is implemented by the inject-scala-plugin sub-project.

  • It is a Scala Compiler Plugin that executes during various phases of compilation similar to the Groovy implementation.

Use via SBT (Scala Build Tool)

A quick proof of concept project using SBT worked just by adding lines below to build.sbt file:

resolvers += Resolver.mavenLocal // Needed now since this is not on a central repo anywhere yet

libraryDependencies += "io.micronaut" % "micronaut-runtime" % "2.0.3.BUILD-SNAPSHOT"

addCompilerPlugin("io.micronaut" % "micronaut-inject-scala-plugin" % "2.0.3.BUILD-SNAPSHOT")

import javax.inject.Singleton
import io.micronaut.context.ApplicationContext

@Singleton
class SomeBean {
  def getMessage() = "hello world"
}

object Main extends App {
  val context = ApplicationContext.run()

  println(context.getBean(classOf[SomeBean]).getMessage)
}

Issues

  • Features not implemented yet:

    • AOP stuff like @Introduction
  • JSR-330 TCK

    • Static injection
    • Scala does not support package-private methods (or fields) in a identical manner to Java. Injected methods in the RoundThing -> Tire -> SpareTire can not implemented in manner identical to Java. Scala supports "private with with respect to a package".

Java

package org.atinject.tck.auto;

class Tire {...

@Inject void injectPackagePrivateMethod() {...

package org.atinject.tck.auto.accessories;

public class SpareTire extends Tire {...

@Inject void injectPackagePrivateMethod() {

Scala

package org.atinject.tck.auto

class Tire {...

@Inject private[auto] def injectPackagePrivateMethod (): Unit = {...
package org.atinject.tck.auto.accessories

public class SpareTire extends Tire {...

@Inject override private[accessories] def injectPackagePrivateMethod(): Unit = {...

This does not compile since "private[accessories]" is more restrictive than "private[auto]". SpareTire.injectPackagePrivateMethod needs to "private[auto]" which is not the exact equivalent of Java package-private. The scopes in Scala need to overlap and it seems that not injecting the overridden method is correct.

  • A lot of unimplemented code that has not been executed by tests ported over from inject-java-test. In some case Scala's "???" method is used. If the code executes such method and "NotImplementedError" is thrown. The intention is that these failures should occur as tests are ported/developed from the Scala version and desired behavior can be flesh out then.

  • Code needs to refactored to be more idiomatic Scala. Some code was ported over from an equivalent Java implementation and auto-translated into Scala by IntelliJ and was left alone if tests passed. First priority was to make it work.

  • There was some code that was translated over that may not be needed yet. This was done early in development where I was trying emulate too closely what Java or Groovy versions were trying to do. Some of this was just removed.

  • Support for Scala built-in type like List, Option (as opposed to Java Optional).

    • Would require modification to AbstractBeanDefinition.getBeanForMethodArgument and getBeanForConstuctorArgument methods. This will be trickier to avoid dependencies on Scala stuff in a non-Scala setting.
  • Dealing different versions of Scala has not been explored yet, like 2.12.x vs 2.13.x not to mention the upcoming Scala 3 (Dotty) release.

  • How does a project using SBT (Scala Build Tool) use this.

  • Problems with @PostContruct and @PreDestroy annotated methods in Scala that throw Exceptions. The Scala version of io.micronaut.inject.close.BeanCloseOrderSpec fails with "java.lang.ClassFormatError: Illegal class name "throws[java/io/IOException]" in class file io/micronaut/inject/close/$CDefinitionClass". This appears to be a problem with micronaut-core generation of the *DefinitionClass.