Scala 反射,查找并实例化具有给定注释的所有类

sun*_*ant 5 reflection annotations scala

我想使用反射在运行时查找具有给定注释的所有类,但是我不知道如何在 Scala 中执行此操作。然后,我想要获取注释的值并动态实例化映射到关联注释的值的每个带注释的类的实例。

这就是我想做的:

package problem
import scala.reflect.runtime._

object Program {

  case class Foo (key: String) extends scala.annotation.StaticAnnotation

  case class Bar ()
  @Foo ("x")
  case class Bar0 extends Bar
  @Foo ("y")
  case class Bar1 extends Bar
  @Foo ("z")
  case class Bar2 extends Bar

  def main (args : Array[String]): Unit = {

    // I want to use reflection to build
    // the following dynamically at run time:
    // val whatIWant: Map [String, Bar] =
    //   Map("x" -> Bar0 (), "y" -> Bar1 (), "z" -> Bar2 ())
    // (it's a map of attribute key -> an instance
    // of the type that has that attribute with that key)
    val whatIWant: Map [String, Bar] = ?
  }
}
Run Code Online (Sandbox Code Playgroud)

并且,为了能够更好地解释自己,以下是我在 C# 中解决问题的方法。

using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;

namespace scalaproblem
{
    public class FooAttribute : Attribute
    {
        public FooAttribute (String s) { Id = s; }
        public String Id { get; private set; }
    }

    public abstract class Bar {}

    [Foo ("x")]
    public class Bar0: Bar {}

    [Foo ("y")]
    public class Bar1: Bar {}

    [Foo ("z")]
    public class Bar2: Bar {}

    public static class AttributeExtensions
    {
        public static TValue GetAttributeValue<TAttribute, TValue>(this Type type, Func<TAttribute, TValue> valueSelector) 
            where TAttribute : Attribute
        {
            var att = type.GetCustomAttributes (typeof(TAttribute), true).FirstOrDefault() as TAttribute;
            if (att != null)
                return valueSelector(att);
            return default(TValue);
        }
    }

    public static class Program
    {
        public static void Main ()
        {
            var assembly = Assembly.GetExecutingAssembly ();
            Dictionary<String, Bar> whatIWant = assembly
                .GetTypes()
                .Where (t => Attribute.IsDefined (t, typeof(FooAttribute)))
                .ToDictionary (t => t.GetAttributeValue((FooAttribute f) => f.Id), t => Activator.CreateInstance (t) as Bar);

            whatIWant.Keys.ToList().ForEach (k => Console.WriteLine (k + " ~ " + whatIWant [k]));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

lmm*_*lmm 3

最实用的答案是使用反射库扫描类路径(或其子集)以查找具有特定注释的所有类;然后,您可以使用 Java 反射 API 或 scala 反射来实例化它们。

(请注意,这不是 100% 可靠,因为例如类加载器允许是动态的,因此可能有一个类不会出现在扫描中。但实际上,对于“正常”用例(即从普通的jar文件)它运行良好)