Java source level annotation processing + byte code level annotation processing __ (3) core_java_advanced

Source: Internet
Author: User
Tags rounds

"0" README

0.1) This text description is transferred from core Java Volume 2, designed to learn the basics of Java source-level annotation processing + bytecode-level annotation processing ;

--------------------------------------------------------------------------------------------------------------- ---------

"1" Source level annotation processing

1 One of the uses of annotations: automatically generate "attached files" containing additional information about the program. Java EE 5 uses annotations to greatly simplify the programming model.
2 The source level annotation is to add the annotation processor to the Java compiler.
3 to see a litchi: we have written a program that can automatically generate bean information classes. The program uses an annotation to mark the Bean's properties, and then runs a tool to parse the source file, analyze its annotations, and finally output the source file for the Bean information class;

4 provide @property annotations: to avoid the drudgery of writing bean information classes, we provide a @Property annotation that can be used to tag the property's picker or set, as follows:

@Property
String GetTitle ()//Fetch
{return
    title;
} or
@Property (editor= "Titlepositioneditor") public
void settitleposition (int p)  //Setup
{
    Titleposition = P;
}

5) @Property definition of annotations

Package com.corejava.chapter10_6;
Import java.lang.annotation.*;
@Documented 
@Target (elementtype.method)
@Retention (retentionpolicy.source) public
@interface Property
{
   String editor () Default "";
}

6 to automatically generate a Bean information class named Beanclass, we want to implement the following tasks:

T1) Write a source file Beanclassbeaninfo.java, inherit from Simplebeaninfo, cover getpropertydescriptors method;

T2) for each annotated method, the property name can be recovered by removing the get or set prefix and then lowercase the remainder.

T3) for each attribute, write a statement to construct the PropertyDescriptor;

T4) If the property has an editor, then write a method to invoke the Setpropertyeditorclass;

T5) writing code returns an array that contains all the property descriptors; see a Litchi (for the following annotation in the Chartbean class, it will be converted to:)

@Property (editor= "Titlepositioneditor") public
void settitleposition (int p)
{
    titleposition = p;
}

will be converted to:

public class Chartbeanbeaninfo extends Java.beans.SimpleBeanInfo
{public
    java.beans.propertydescriptor[] GetProperties ()
    {
        java.beans.PropertyDescriptor titlepositiondescriptor  = new Java.beans.PropertyDescriptor ("Titleposition", chartbean.class);
        Titlepositiondescriptor.setpropertyeditorclass (titlepositioneditor.class) ...
        return new java.beans.propertydescriptor[]
        {
            titlepositiondescriptor,
            ...
        }
}}

6.1) If we can locate all the methods that have been marked with @Property attribute, then all of these are easy to implement.

7 Starting with the Java SE6, we can add the annotation processor to the Java compiler.

7.0) in order to invoke the annotation processing mechanism, it is necessary to run Javac-processor processorclassname1,processorclassname2,... sourcefiles 7.1) The compiler locates the annotations in the source code and then selects the appropriate annotation processor. Each annotation processor is executed sequentially. If a note processor creates a new source file, the process is repeated. If a processing loop does not generate any new source files, then compile all the source files.

7.2) The following figure shows how @Property annotations are handled;

8) Custom annotation processor

8.1) annotation processor to extend the abstractprocessor and rewrite the process method:

public Boolean process (SET<? extends typeelement> annotations, roundenvironment roundenv)

8.1.1) The process method has two parameters: One is the set of annotations to be processed in this round, and the other is a roundenv reference containing information about the current processing rounds;

8.1.2 in the process method , we iterate over all the annotated methods, for each method, we peel the get, set, and is prefixes in their names and rewrite the letters next to each other to lowercase to obtain the property name;

public Boolean process (set<. Extends typeelement> annotations, roundenvironment roundenv)
   {for
      ( Typeelement t:annotations)
      {
         map<string, property> props = new linkedhashmap<> ();         
         For (Element E:roundenv.getelementsannotatedwith (t))
         {
             Props.put (the property name, E.getannotation ( Property.class));
         }
    Write Bean info source file return
    ture;
}

8.2 Specify the type of annotation supported by the processor:

@SupportedAnnotationTypes ("Sourceannotations.property") public
class Beaninfoannotationprocessor extends Abstractprocessor

8.3) Compile the annotation processor and run

Compile note Processor: E:\bench-cluster\cloud-data-preprocess\corejavaadvanced\src>javac com/corejava/chapter10_6/ Beaninfoannotationprocessor.java
Run: E:\bench-cluster\cloud-data-preprocess\corejavaadvanced\src>javac- Processor Com.corejava.chapter10_6.BeanInfoAnnotationProcessor  Com/corejava/chapter10_6/chartbean.java
Result: You can then view the automatically generated Chartbeanbeaninfo.java file;

8.4 To view the behavior of the annotation processor, you can add xprintrounds to the Javac command. Get the following output:

Attention)for source code, visit https://github.com/pacosonTang/core-java-volume/tree/master/ Corejavaadvanced/chapter10/10_6

Package com.corejava.chapter10_6;
Import java.beans.*;
Import java.io.*;
Import java.util.*;
Import javax.annotation.processing.*;
Import javax.lang.model.*;
Import javax.lang.model.element.*;
Import javax.tools.*;

Import javax.tools.diagnostic.*;
 /** * This class is the processor which analyzes property annotations. * @version 1.11 2012-01-26 * @author Cay Horstmann///Specify processor-supported annotation types: @SupportedAnnotationTypes ("Com.corejava.chapter10 _6.property ") @SupportedSourceVersion (sourceversion.release_8)//Custom annotation processor public class Beaninfoannotationprocessor The extends Abstractprocessor {//Process method has two parameters://Annotations One is the set of annotations to be processed in this round, and the other is a roundenv reference that contains information about the current processing rounds; @Over Ride public Boolean process (SET&LT;. extends typeelement> annotations, roundenvironment roundenv) {for (Ty
         Peelement t:annotations) {map<string, property> props = new linkedhashmap<> ();
         String beanclassname = null; for (Element E:roundenv.getelementsannOtatedwith (t)) {String mname = E.getsimplename (). toString ();
            String[] prefixes = {' Get ', ' set ', ' is '};
            Boolean found = false;
               for (int i = 0;!found && i < prefixes.length i++) if (Mname.startswith (prefixes[i))
                  {found = true;
                  int start = Prefixes[i].length ();
                  String name = Introspector.decapitalize (mname.substring (start));
               Props.put (name, E.getannotation (Property.class)); } if (!found) Processingenv.getmessager (). Printmessage (Kind.error, "@Property must be appli
            Ed to GetXXX, setxxx, or Isxxx method ", e);
                     else if (beanclassname = null) Beanclassname = ((typeelement) e.getenclosingelement ()). Getqualifiedname ()
         . toString (); The try {if (beanclassname!= null) writebeaninfofile (BeanclasSname, props);
         catch (IOException e) {e.printstacktrace ();
   } return true;
    }/** * Writes the source file for the BeanInfo class.
   * @param beanclassname The name of the Bean class * @param props a map of property names and their annotations * *
	   private void Writebeaninfofile (String beanclassname, map<string, property> props) throws IOException { Create output file Javafileobject sourcefile = Processingenv.getfiler (). Createsourcefile (Beanclassname + "BeanIn
      Fo ");
      PrintWriter out = new PrintWriter (Sourcefile.openwriter ());
      int i = Beanclassname.lastindexof (".");
         The code to write the source file is straightforward, just a series of out.println statements if (i > 0) {out.print ("package");
         Out.print (beanclassname.substring (0, i));
      Out.println (";");
      } out.print ("public class");
      Out.print (beanclassname.substring (i + 1)); Out.println ("BeanInfo extenDS Java.beans.SimpleBeanInfo ");
      Out.println ("{");
      Out.println ("Public java.beans.propertydescriptor[] Getpropertydescriptors ()");
      Out.println ("{");
      Out.println ("Try");
      Out.println ("{"); For (map.entry<string, property> e:props.entryset ()) {Out.print ("Java.beans.PropertyDescr
         Iptor ");
         Out.print (E.getkey ());
         OUT.PRINTLN ("descriptor");
         Out.print ("= new Java.beans.PropertyDescriptor (\");
         Out.print (E.getkey ());
         Out.print ("\", ");
         Out.print (Beanclassname);
         Out.println (". Class);";
         String ed = E.getvalue (). Editor (). toString ();
            if (!ed.equals ("")) {Out.print ("");
            Out.print (E.getkey ());
            Out.print ("Descriptor.setpropertyeditorclass (");
            Out.print (ed);
         Out.println (". Class);"; } out.println ("Return new Java.beaNs.
      Propertydescriptor[] ");
      Out.print ("{");
      Boolean-i = true;
         For (String P:props.keyset ()) {if (a) = false;
         Else Out.print (",");
         Out.println ();
         Out.print ("");
         Out.print (P);
      Out.print ("descriptor");
      } out.println ();
      Out.println ("};");
      Out.println ("}");
      Out.println ("catch (Java.beans.IntrospectionException e)");
      Out.println ("{");
      Out.println ("E.printstacktrace ();");
      OUT.PRINTLN ("return null;");
      Out.println ("}");
      Out.println ("}");
      Out.println ("}");
   Out.close (); }
}

Package com.corejava.chapter10_6;
Import java.lang.annotation.*;

@Documented
@Target (elementtype.method)
@Retention (retentionpolicy.source) public
@interface Property
{
   String editor () Default ""; 
}

"2" Bytecode engineering (中文版 version, see HTTP://WWW.INFORMIT.COM/ARTICLES/ARTICLE.ASPX?P=2027052&SEQNUM=7)

0 For complete source code about byte-code engineering, please visit:Https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter10/10_7
1 The level of processing annotations (levels): L1) Run period level:For concrete examples, see http://blog.csdn.net/pacosonswjtu/article/details/50719233L2) Source level:For concrete examples, see this chapter "1";L3) byte-code level:For concrete examples, see this chapter "2";2 The class file for annotation processing:class file format, which is quite complex, and in the absence of a special class library, handling class files can be challenging. BCEL (byte code Engineering Library), that is, the bytecode engineering class libraries, is such a special class library one;(Dry Goods--introduction of Bcel, bytecode Engineering class library) 3 Use Bcel to add log information to the annotated method. 3.1 If a method is so annotated:@LogEntry (Logger=loggername)3.2 At the beginning of the method, we add:Logger.getlogger (Loggername). Entering (ClassName, MethodName);4) Look at a litchi: 4.1)If you do the following annotation on the Hashcode method of the Item class: @LogEntry (logger= "global") public int hashcode ();4.2 Then, when the method is invoked at any time, a message similar to the one printed below will be reported:Aug, Hashcode, Item finer:entry5 in order to achieve this task, we need to follow the following points (points): p1)Loading the byte code in the class file;p2)Locate all the methods;p3)For each method, check that it is not having a logentry annotation;P4)If so, add the bytecode for the instructions listed below at the beginning of the method:

LDC Loggername
invokestatic java/util/logging/logger.getlogger: (ljava/lang/string;) Ljava/util/logging/logger ;
LDC ClassName
LDC methodname
invokevirtual java/util/logging/logger.entering: (ljava/lang/string; ljava/lang/string;) V
Attention)Inserting these bytecode looks complicated, but Bcel makes it simple; 6) Look at a litchi: 6.1)How to add a record log directive to a Item.java file
E:\BENCH-CLUSTER\CLOUD-DATA-PREPROCESS\COREJAVAADVANCED\SRC>JAVAC-CP.; COM/COREJAVA/CHAPTER10_7/BCE L-6.0-snapshot.jar Com/corejava/chapter10_7/entrylogger.java
E:\bench-cluster\ CLOUD-DATA-PREPROCESS\COREJAVAADVANCED\SRC>JAVA-CP.; Com/corejava/chapter10_7/bcel-6.0-snapshot.jar Com.corejava.chapter10_7.EntryLogger com.corejava.chapter10_7. Item 
Adding logging instructions to com.corejava.chapter10_7.Item.equals
adding logging to Com.corejava.chapter10_7.Item.hashCode
Dumping E:\bench-cluster\cloud-data-preprocess\CoreJavaAdvanced\src\ Com\corejava\chapter10_7\item.class
6.2 After the item class file has been revised and modified Java before the operation of the following:
Javap-c Item, you can see those instructions inserted at the beginning of the hashcode, Equals, and CompareTo methods;
E:\bench-cluster\cloud-data-preprocess\corejavaadvanced\src>javap-c Com.corejava.chapter10_7.Item Compiled From ' Item.java ' public class Com.corejava.chapter10_7.Item {public Com.corejava.chapter10_7.Item (java.lang.String,
    int); code:0: Aload_0 1:invokespecial #1//Method Java/lang/object. " <init> ":() V 4:aload_0 5:aload_1 6:putfield #2//Field Description:lja
       va/lang/string;
      9:aload_0 10:iload_2 11:putfield #3//Field partnumber:i
    14:return public java.lang.String getdescription ();
       code:0: Aload_0 1:getfield #2//Field description:ljava/lang/string;
    4:areturn public java.lang.String toString (); code:0: New #4//class Java/lang/stringbuilder 3:dup 4:invokespecial # 5//Method Java/lang/stringbuilder. " <init> ":(V 7:LDC #6//String [description= 9:invokevirtual #7//Meth
      OD java/lang/stringbuilder.append: (ljava/lang/str ing;) ljava/lang/stringbuilder;
      12:aload_0 13:getfield #2//Field description:ljava/lang/string; 16:invokevirtual #7//Method java/lang/stringbuilder.append: (ljava/lang/str ing;) ljava/lang/stringbuild
      Er 19:LDC #8//String, partnumber= 21:invokevirtual #7//Method java/l
      Ang/stringbuilder.append: (ljava/lang/str ing;) ljava/lang/stringbuilder;
      24:aload_0 25:getfield #3//Field partnumber:i
      28:invokevirtual #9//Method Java/lang/stringbuilder.append: (I) ljava/lang/s Tringbuilder; 31:LDC #10//String] 33:invokevirtual #7//Method Java/lang/stringbu Ilder.append: (ljava/lang/str ing;) LjAva/lang/stringbuilder; 36:invokevirtual #11//Method java/lang/stringbuilder.tostring: () ljava/lang/string;
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.