2012-07-13 14 views
9

पर एनोटेशन मामले वर्ग मैदान पर परिभाषित का उपयोग कैसे मैं निम्नलिखित जावा एनोटेशन परिभाषित किया हैरनटाइम

@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.FIELD}) 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface MyAnnotation { 
    String value() default ""; 
    } 

और मैं निम्नलिखित स्केला मामले वर्ग परिभाषित किया है:

@Prefer("xyz") 
case class TestAnno(arg1 : String, @Prefer("abc") agr2 : String) 

मैं प्रतिबिंब का उपयोग कर कक्षा स्तर के मामले में परिभाषित एनोटेशन को सक्षम करें लेकिन मैं arg2 केस श्रेणी TestAnno के सदस्य के लिए परिभाषित एनोटेशन तक पहुंच नहीं पा रहा हूं। कोड को डी-संकलित करते हुए मैं देखता हूं कि न तो परिवर्तनीय घोषणा या इसके स्केल एक्सेसर को एनोटेशन लगता है। केवल कन्स्ट्रक्टर परिभाषा और copy विधि वर्ग की घोषणा में परिभाषित मानकों के लिए एनोटेशन को बनाए रखने लगती है।

वहाँ क्षेत्रों मामले कक्षा में घोषित के लिए एनोटेशन उत्पन्न करने के लिए स्केला संकलक मजबूर करने के लिए कुछ अन्य रास्ता नहीं है या मैं निर्माता पढ़ सकते हैं और ASM ByteCode Library या ParaNamer के रूप में एक पुस्तकालय में इस तरह का उपयोग खोजने के लिए जो पैरामीटर जो एनोटेशन की है? एक समाधान की आवश्यकता है जो मुख्य रूप से स्कैला केस कक्षाओं के लिए काम करेगी।

उत्तर

2

मैंने कुछ खोज किया और दो समाधानों के साथ आया है। टिप्पणियाँ, Suggesstions, सुधार स्वागत है, मैंने इस जवाब को विकी के रूप में चिह्नित किया है। पहला वाला ScalaBeans और ParaNamer पर आधारित है।

def valNamesWithAnnotations[T <: AnyRef](obj : T)(implicit m : Manifest[T]) : List[(String, List[java.lang.annotation.Annotation])] = { 
    val descriptor = descriptorOf(obj.getClass) 

    val c = descriptor.beanType.erasure 

    val constructor: Option[Constructor[_]] = { 
     if (c.getConstructors().isEmpty) None 
     else Some(c.getConstructors()(0).asInstanceOf[Constructor[_]]) 
    } 

    val paranamer = new BytecodeReadingParanamer 
    val ctorParameterNames = constructor.map(paranamer.lookupParameterNames(_)).getOrElse(scala.Array[String]()).toList 
    val ctorParamAnnos = constructor.getOrElse(sys.error("Cannot find constructor entry for class " + c.getName)).getParameterAnnotations 

    val builder = List.newBuilder[(String, List[java.lang.annotation.Annotation])] 
    val paramIter = ctorParameterNames.iterator 
    val annoIter = ctorParamAnnos.iterator 

    while(paramIter.hasNext && annoIter.hasNext) { 
     builder += ((paramIter.next, annoIter.next.toList)) 
    } 

    builder.result 
    } 

दूसरा दृष्टिकोण ScalaSignatures का उपयोग करता है और इस SO answer पर आधारित है:

case class TestAnno(arg1 : String, @(Prefer @field)("abc") agr2 : String) 
यहाँ

अधिक जानकारी http://www.scala-lang.org/api/current/#scala.annotation.meta.package

9

तुम बस निम्नलिखित कार्य करने होंगे समाधान काम किया, लेकिन आईएमएचओ यह के लिए बहुत अधिक बॉयलरप्लेट है उपयोगकर्ता।

आप मानक प्रतिबिंब एपीआई के साथ कन्स्ट्रक्टर तर्कों पर एनोटेशन पढ़ सकते हैं। मुझे एक मैक्रो कार्यान्वयन के लिए इसकी आवश्यकता थी।

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

import scala.annotation.StaticAnnotation 
final class min(i: Long) extends StaticAnnotation 

case class Foo(@min(1) c: String) 
import scala.reflect.runtime.universe._ 
symbolOf[Foo].asClass.primaryConstructor.typeSignature.paramLists.head.head.annotations 

// Exiting paste mode, now interpreting. 

import scala.annotation.StaticAnnotation 
defined class min 
defined class Foo 
import scala.reflect.runtime.universe._ 
res0: List[reflect.runtime.universe.Annotation] = List(min(1L)) 
+0

प्रतिबिंब द्वारा इन पैरामीटरों को आप कैसे एक्सेस करते हैं, इस पर निर्भर करते हुए, आपको '@ setter',' @ getter', या '@ param' को इसके बजाय या @ @ field' के साथ जोड़ना पड़ सकता है। (आप उन सभी के साथ प्रयास कर सकते हैं, और उन्हें एक-एक करके हटा सकते हैं।) – al3xar

5

क्वेंटिन के:

def valNamesWithAnnotations[C: ClassManifest] : List[(String, List[java.lang.annotation.Annotation])] = { 
    val cls = classManifest[C].erasure 
    val ctors = cls.getConstructors 

    assert(ctors.size == 1, "Class " + cls.getName + " should have only one constructor") 
    val sig = ScalaSigParser.parse(cls).getOrElse(sys.error("No ScalaSig for class " + cls.getName + ", make sure it is a top-level case class")) 

    val classSymbol = sig.parseEntry(0).asInstanceOf[ClassSymbol] 
    assert(classSymbol.isCase, "Class " + cls.getName + " is not a case class") 

    val tableSize = sig.table.size 
    val ctorIndex = (1 until tableSize).find { i => 
     sig.parseEntry(i) match { 
     case m @ MethodSymbol(SymbolInfo("<init>", owner, _, _, _, _), _) => owner match { 
      case sym: SymbolInfoSymbol if sym.index == 0 => true 
      case _ => false 
     } 
     case _ => false 
     } 
    }.getOrElse(sys.error("Cannot find constructor entry in ScalaSig for class " + cls.getName)) 

    val paramsListBuilder = List.newBuilder[String] 
    for (i <- (ctorIndex + 1) until tableSize) { 
     sig.parseEntry(i) match { 
     case MethodSymbol(SymbolInfo(name, owner, _, _, _, _), _) => owner match { 
      case sym: SymbolInfoSymbol if sym.index == ctorIndex => paramsListBuilder += name 
      case _ => 
     } 
     case _ => 
     } 
    } 

    val paramAnnoArr = ctors(0).getParameterAnnotations 
    val builder = List.newBuilder[(String, List[java.lang.annotation.Annotation])] 

    val paramIter = paramsListBuilder.result.iterator 
    val annoIter = paramAnnoArr.iterator 

    while(paramIter.hasNext && annoIter.hasNext) { 
     builder += ((paramIter.next, annoIter.next.toList)) 
    } 

    builder.result 
    } 
+0

एनोटेशन जानकारी कैसे पहुंचा जा सकता है? – bashan