Scala Java
Switch branches/tags
Nothing to show
Permalink
Failed to load latest commit information.
.settings
src/main
.classpath
.gitignore
.project
README.textile
pom.xml

README.textile

Scala “Bug” with CDI

Overview

“Sometimes”, Scala creates public final methods, although the .scala source defines
no public final method at all.

There are two things that CDI doesn’t like (which Scala “sometimes” generates):

1. public final methods
2. public fields

public final method: The Bug

Referencing a parent field from a closure / inner class triggers this behavior:

@RequestScoped @Named
class IndexBean {
  
  private lazy val log = LoggerFactory.getLogger(classOf[IndexBean])
  def testExecutor() = {
    val executor = Executors.newFixedThreadPool(4);
    executor.submit(new Runnable() { override def run(): Unit = log.debug("Executor is running") })
  }

}

Compiles to:

$ javap -p IndexBean
Compiled from "IndexBean.scala"
public class com.soluvas.scalacdi.IndexBean extends java.lang.Object implements scala.ScalaObject{
    private org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log;
    ...
    public final org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log();

Deploying this app in Weld will throw:

org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437 Normal scoped bean class com.soluvas.scalacdi.IndexBean is not proxyable because the type is final or it contains a final method public final org.slf4j.Logger com.soluvas.scalacdi.IndexBean.com$soluvas$scalacdi$IndexBean$$log() - Managed Bean [class com.soluvas.scalacdi.IndexBean] with qualifiers [@Any @Default @Named].
	at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:225)
	at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:178)
	at org.jboss.weld.util.Proxies.getUnproxyableTypesExceptionInt(Proxies.java:193)
	at org.jboss.weld.util.Proxies.getUnproxyableTypesException(Proxies.java:167)
	at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:110)

public final method: Workaround

Create a local final field to hold the parent instance’s value:

 def testExecutor() = {
    val executor = Executors.newFixedThreadPool(4);
    // this avoids 'log' becoming 'final' like:
    //     private org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log;
    //     public final org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log();
    val log = this.log; 
    executor.submit(new Runnable() { override def run(): Unit = log.debug("Executor is running") })
  }

Which now compiles to:

$ javap -p IndexBean
Compiled from "IndexBean.scala"
public class com.soluvas.scalacdi.IndexBean extends java.lang.Object implements scala.ScalaObject{
    private org.slf4j.Logger log;
    private org.slf4j.Logger log();

public field

I’m not able to reproduce this yet…