Compare the use of C #'s Attribute and Java's @ annotation

Posted by porko2004 on Wed, 29 Dec 2021 11:52:19 +0100

preface:

Annotation @ annotation is a very important part of Java,
Since the launch of version 1.5, it has been widely used in various frameworks and applications,
It has become an important puzzle of Java
C #'s Attribute and @ annotation have similar functions,
It is also used to add dynamic runtime information to classes / interfaces /

Let's take Java's use of annotation as an example,

Java uses annotation: fake a @ Bean

@Bean is the most basic annotation of spring,
Once added, an instance of the class and method is created in the container
This function is not difficult. Now we can implement it ourselves without limiting the life cycle

1. Define a container (actually a Map)

public class MySpringContainer {
	
	public static HashMap<String,Object> theContainer = new HashMap<String, Object>();
	
	public static HashMap<String, Object> getContainer(){
		return theContainer;
	}

}

2. Define annotation @ Bean

The definition of annotation only needs to remember four meta annotations

  1. @Target({ElementType enumeration class, used to specify the scope of use of annotations})
  2. @Retention(RetentionPolicy enumeration type, used to specify the retention of annotation information. Souce is only retained during compilation, Class is saved in the compiled Class file, and RUNTIME is also retained during (VM) program running)
  3. @Documented
  4. @Inherited / / whether it can be inherited is very common. In spring, @ Component inherits @ bean, @ service, @ controller, @ Repository... And @ Component
@Target({ElementType.TYPE})   //Can be set on a class
@Retention(RetentionPolicy.RUNTIME) //Retention policy
@Inherited
@Documented
public @interface Bean {
	
	//The definition of annotation is very similar to that of an interface, and it can only declare methods in it (but its method is essentially an attribute and does not need to be implemented, which is different from that of an interface)
	String O_id();
	
}

3. Arbitrarily define a pojo class and apply annotations

@Bean(O_id = "theOne")   //tip: if the method name is value, you don't need to write O_id
public class Pet {
	
	private String id;
	
	private String name;
	
	private String Owner;

	public String getId() {
		return id;
	}
	public Pet() {
		System.out.println("Parameter free construction method is used");
		id = "deffault";
		name = "deffault";
		Owner = "deffault";
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getOwner() {
		return Owner;
	}
	public void setOwner(String owner) {
		Owner = owner;
	}
}

4. Use reflection to get annotations at run time

After the definition is completed, you need to obtain the class information and obtain the annotation information on the class information,
Write a simple class scanning tool here to check the @ Bean annotation information of the class under the specified package

public class PojoAnnotionScanner {
	
	
	public static void Scan(String packageName) throws Exception {
		List<Class> list = getClazzesInPackage(packageName);
		list.forEach(claz->{
			//Check whether there is Bean tag in Class
			if(claz.getAnnotation(Bean.class)!=null) {
				Bean bean = (Bean) claz.getAnnotation(Bean.class);
				Object obj = new Object();
				try {
					obj = claz.newInstance();
				} catch (Exception e) {
					e.printStackTrace();
				} 
				//If so, put the object and annotation information obtained by Class reflection into our Shanzhai container
				MySpringContainer.getContainer().put(bean.O_id(), obj);
			}
			
		});
	}
	//Gets the Class collection of all classes under the specified enrollment
	private static List<Class> getClazzesInPackage(String packageName) throws Exception {
		ArrayList<Class> list = new ArrayList<>();
		//Get package path
		String packpath = packageName.replace('.', '/');
		//Get the URL of the package
		URL pURL = Thread.currentThread().getContextClassLoader().getResource(packpath);
		//Get the package folder and prepare to traverse the following class file
		File dic = new File(pURL.getPath());
		if(!dic.exists())
			throw new Exception("The package path is incorrect!");
		File[] files = dic.listFiles(filename->{
			if(filename.getName().endsWith(".class"))
				return true;
			return false;});
		
		for(File item : files ) {
			String totalpath = packageName+"."+FilenameUtils.getBaseName(item.getName());
			Class claz = Class.forName(totalpath);
			list.add(claz);
		}
		
		return list;
	}

}

Run test:

public static void main(String[] args) throws Exception {
		//After scanning, you can find the created object in our container
		PojoAnnotionScanner.Scan("pojo");
		Pet the = (Pet) MySpringContainer.theContainer.get("theOne");
		System.out.println(the.getId()+the.getName()+the.getOwner());
}

Operation results:

Parameter free construction method is used
deffaultdeffaultdeffault


Of course, you can also define another @ Value annotation to assign a Value to the attribute,
Then check the method again, and then get all fields in Class through reflection

C # use Attribute to copy a [Bean]

1. Container

public class MySpringContainer
{
    public static Dictionary<string, Object> springContainer = new Dictionary<string, object>();

    public static Dictionary<string, Object> GetConainer()
    {
        return springContainer;
    }
}

2. Define Attribute

/// <summary>
 ///Define [Bean annotation, limited to type, can create an instance object like Spring]
 /// </summary>
 ///C #'s annotation needs to be decorated with [AttributeUsage], and the three parameters represent
 ///AttributeTargets annotation application type, equivalent to @ Target
 ///Can AllowMultiple be in a class / interface / method Reuse on
 ///Whether Inherited is allowed to be Inherited
 [AttributeUsage(AttributeTargets.Class,AllowMultiple = false,Inherited = true)]
 public class Bean:System.Attribute
 {
     //C # annotation inherits from Attribute. Like an ordinary class, attributes and methods can be defined and instantiated normally

	 //But when Atrribute is applied as an annotation to a class / interface / method You can only use its constructor to receive parameters or assign values to properties
	 //Therefore, many constructors can be defined to receive different forms of parameters,
	 //This is different from the @ annotation method of Java, but the purpose is the same, that is to save the information in the annotation
     public string O_ID { get; }

     public Bean(string O_ID)
     {
         this.O_ID = O_ID;  
     }
 }

3.poco class

 [Bean("TheSingle")]
 public class Pet
 {
     public string ID  { get; set; }

     public string Name { get; set; }

     public string OwnerName { get; set; }

     public Pet()
     {
         ID = "DefaultID";
         Name = "DefaultName";
         OwnerName = "Zhang San";
     }
     public override string ToString()
     {
         return "Pets ID:" + ID + "name:" + Name + "Host name:" + OwnerName;
     }
 }

4. Get comments by reflection

public static void Scan(string packageName)
{
	//C# getting the Type of all classes in dll is very simple
    List<Type> list = Assembly.Load(packageName).GetTypes().ToList();
	//Traverse the Type collection to determine whether there is an Attribute of the Bean,
    list.ForEach(type =>
    {
        if (type.GetCustomAttribute(typeof(Bean))!=null)
        {
        	//If so, register an instance of this type in the container
            Bean bean = (Bean)type.GetCustomAttribute(typeof(Bean));
            MySpringContainer.GetConainer().Add(bean.O_ID, Activator.CreateInstance(type));
        }
    });
       
}

Test:

static void Main(string[] args)
{
    ClassScanner.Scan("AttributeTest");
    Pet pet1 = (Pet)MySpringContainer.springContainer["TheSingle"];
    Console.WriteLine(pet1);  
}

Summary:

Same as:
Both Attribute and @ annotation need to serve reflection
Are dynamic information added at run time
Different;
Attribute can be an ordinary class in essence, @ annotation is neither a class nor an excuse
Attribute saves information through its constructor, and @ annotation saves information through its method attribute

Topics: Java C# Spring