【问题标题】:Is is possible to capture the type parameter of a trait using Manifests in Scala 2.7.7?是否可以使用 Scala 2.7.7 中的清单捕获特征的类型参数?
【发布时间】:2009-12-18 20:50:44
【问题描述】:

我正在 Scala 中编写一个 ServletUnitTest trait 来为 ServletUnit 提供一个方便的 API。我有类似的想法:

/**
 * Utility trait for HttpUnit/ServletUnit tests
 * 
 * @param [T] Type parameter for the class under test
 */
trait ServletUnitTest[T <: HttpServlet] {
   /**
    * Resource name of the servlet, used to construct the servlet URL.
    */
   val servletName: String

   /**
    * Servlet class under test
    */
   implicit val servletClass: Manifest[T] 

   /**
    * ServletUnit {@link ServletRunner}
    */
   sealed lazy val servletRunner: ServletRunner = {
      val sr = new ServletRunner();
      sr.registerServlet(servletName, servletClass.erasure.getName);
      sr
   }

   /**
    * A {@link com.meterware.servletunit.ServletUnitClient}
    */
   sealed lazy val servletClient = servletRunner.newClient

   /**
    * The servlet URL, useful for constructing WebRequests
    */
   sealed lazy val servletUrl = "http://localhost/" + servletName

   def servlet(ic: InvocationContext) = ic.getServlet.asInstanceOf[T]
}

class MyServletTest extends ServletIUnitTest[MyServlet] {
   val servletName = "download"

   // ... test code ...
}

此代码未按编写方式编译,但希望我的意图很明确。有没有办法做到这一点(有或没有清单)?

【问题讨论】:

    标签: scala servletunit


    【解决方案1】:

    在研究这个主题时,我发现了 Jorge Ortiz 的解决方案 in this scala-list post,它对我有用,而且比 Aaron 的更简单。 本质上,他的解决方案是(释义):

      trait A[T] {
        implicit val t: Manifest[T]
      }
    
      class B[T: Manifest] extends A[T] {
        override val t = manifest[T]
      }
    

    (我在 2011 年写这篇文章时忽略了与 2.7.7 兼容的 OP 请求...)

    【讨论】:

      【解决方案2】:

      目前,Scala 将特征表示为接口,因此该技术将起作用。但是,这种实现 trait 的方法存在一些问题,当方法被添加到 trait 时,实现类不一定会重新编译,因为接口表示只有一个转发方法,该方法指向实际具体实现该方法的另一个类。作为对此的回应,今年早些时候有人谈到在运行时使用接口注入到 JVM 中来解决这个问题。如果使用这种方法的能力,那么特征的类型信息将在您捕获之前丢失。

      【讨论】:

      • 我可能是错的,但我认为由于 Manifest 是由编译器提供的,因此无论特征是如何实现的,我的技术都可以工作。另一方面,基于运行时反射的技术可能会遇到麻烦。
      • 对。我猜这就是为什么所有这些现在都没有正式记录的原因,因为底层实现可能会改变你。
      【解决方案3】:

      类型信息可通过 Java 反射 API 访问。它不漂亮,但它有效:

      trait A[T]{
        def typeParameter = {
          val genericType = getClass.getGenericInterfaces()(0).asInstanceOf[ParameterizedType]
          genericType.getActualTypeArguments()(0)
        }
      }
      class B extends A[Int]
      
      new B().typeParameter -> java.lang.Integer
      

      应该添加一些不变的检查我只实现了快乐的路径。

      【讨论】:

      • 我认为擦除会使反射无法使用,但我想不会,因为测试类没有参数化。谢谢!
      【解决方案4】:

      我找到了一个可行的解决方案,但它非常尴尬,因为它要求测试类在评估任何 trait 的惰性 val 之前调用 trait 上的方法 (clazz)。

      /**
       * Utility trait for HttpUnit/ServletUnit tests
       * 
       * @param [T] Type parameter for the class under test
       */
      trait ServletUnitTest[T <: HttpServlet] {
         /**
          * Resource name of the servlet, used to construct the servlet URL.
          */
         val servletName: String
      
         /**
          * Servlet class under test
          */
         val servletClass: Class[_] // = clazz
         protected def clazz(implicit m: Manifest[T]) = m.erasure
      
         /**
          * ServletUnit {@link ServletRunner}
          */
         sealed lazy val servletRunner: ServletRunner = {
            val sr = new ServletRunner();
            sr.registerServlet(servletName, servletClass.getName);
            sr
         }
      
         /**
          * A {@link com.meterware.servletunit.ServletUnitClient}
          */
         sealed lazy val servletClient = servletRunner.newClient
      
         /**
          * The servlet URL, useful for constructing WebRequests
          */
         sealed lazy val servletUrl = "http://localhost/" + servletName
      
         def servlet(ic: InvocationContext) = ic.getServlet.asInstanceOf[T]
      }
      
      class MyServletTest extends ServletIUnitTest[MyServlet] {
         val servletName = "download"
         val servletClass = clazz
      
         // ... test code ...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-08
        • 2015-06-18
        • 1970-01-01
        • 2021-07-22
        • 2021-10-28
        • 1970-01-01
        相关资源
        最近更新 更多