Scala 反射,使用给定的注释查找和实例化所有类 [英] Scala reflection, finding and instantiating all classes with a given annotation
问题描述
我想在运行时使用反射来查找具有给定注释的所有类,但是我不知道如何在 Scala 中这样做.然后我想获取注解的值并动态实例化每个注解类的实例映射到关联注解的值.
I want use reflection to find, at runtime, all classes that have a given annotation, however I can't work out how to do so in Scala. I then want to get the value of the annotation and dynamically instantiate an instance of each annotated class mapped to the value of the associated annotation.
这是我想要做的:
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] = ?
}
}
而且,为了能够更好地解释自己,下面是我将如何在 C# 中解决问题.
And, in the hope of being able to explain myself better, here's how I would solve the problem in 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]));
}
}
}
推荐答案
最实用的答案是使用 reflections library 扫描具有特定注释的所有类的类路径(或其子集);然后,您可以使用 Java 反射 API 或 Scala 反射来实例化它们.
The most practical answer is to use the reflections library to scan the classpath (or a subset of it) for all classes with a particular annotation; you can then instantiate those using either the Java reflection API or scala reflection.
(请注意,这不是 100% 可靠的,因为例如类加载器允许是动态的,因此可能有一个类不会出现在扫描中.但实际上,对于正常"用例(即从普通 jar 文件加载类)效果很好)
(Note that this is not 100% reliable because e.g. classloaders are allowed to be dynamic, so it's possible to have a class that doesn't show up in the scan. But in practice, for "normal" use cases (i.e. loading classes from ordinary jar files) it works well)
这篇关于Scala 反射,使用给定的注释查找和实例化所有类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!