Skip to content

ceefour/scala-cdi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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…

About

Scala CDI Experiments

Resources

Stars

Watchers

Forks

Packages

No packages published