Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Creating Annotations in Java

See in this article how to create Java Annotations and make use of reflection properly

In this article we will see two very important and interesting issues in the Java world: the annotations and reflection feature (reflection). Our aim is to create a useful annotation for a given task in coding our system, but doing so is not possible without us having the reflection of knowledge.

We will study the theories of both concepts and we will see later how to apply those resources.

Reflection

When developing a software able to define various features statically, using class methods ever created, set attributes also previously created and etc. Most often, it is sufficient for the construction of a project, but there are exceptions and this is exactly what they will study.

Consider how Hibernate framework can know that our Client class has a setName() method is in his encoding sure there is no reference to this class? Remember that Hibernate developers or any other framework never imagined that you would need to use the Client class. They developed such a feature of more general as possible in order to adapt to any business rule.

The answer to this question is: Reflection, since its use is commonly applied to many frameworks in order to make the same pluggable, such as Hibernate, Spring, CDI, etc. The javax.reflection possible package to be made calls to methods, attributes, etc. at runtime, that is, we instantiate a class without knowing what the class. But how is this possible?

First we build a Java Bean that will be used throughout our article with a simple class called Client with its attributes and access methods (getters and setters), as shown in Listing 1.

Listing 1. Client Class

 import java.util.Date;
  public class Client {
         private String name;
         private int code;
         private Date birthDay;
         private String fatherName;
         private String motherName;
         private String address;
         public String getName() {
               return name;
         }
         public void setName(String name) {
               this.name = name;
         }
         public int getCode() {
               return code;
         }
         public void setCode(int code) {
               this.code = code;
         }
         public Date getBirthDay() {
               return birthDay;
         }
         public void setBirthDay(Date birthDay) {
               this.birthDay = birthDay;
         }
         public String getFatherName() {
               return fatherName;
         }
         public void setFatherName(String fatherName) {
               this.fatherName = fatherName;
         }
         public String getMotherName() {
               return motherName;
         }
         public void setMotherName(String motherName) {
               this.motherName = motherName;
         }
         public String getAddress() {
               return address;
         }
         public void setAddress(String address) {
               this.address = address;
         }     
  }

There are three features that reflection allows access at runtime: Class, Field and Method. With these three you can do everything you need with any kind of class. First let's learn a little about the methods that provides reflection and then we will use as an example the bean created in Listing 1 to solve real problems. Notice in Listing 2.

Listing 2. Using getClass()

public static void main(String[] args) {
               Client client = new Client();
               System.out.println(client.getClass().getName());
         } 
Output: Client 

The first method is the getClass() and with it we captured the client object's class, which in our case is the Client class. The getClass() returns a Class object, which has many methods to manipulate the Client class, such as getName(), getModifiers, getConstructor and etc.

We use up an object to return to his class, but we could use the Client class itself for this information, the same as the one shown in Listing 3.

Listing 3. Using Client.class

  public static void main(String[] args) {
               Client client = new Client();
               System.out.println(Client.class.getName());
         }

With Class in hand we can begin to unravel the resources contained within it, for example, attributes, methods, modifiers, builders, etc. Let's see the names of all the attributes in Listing 4.

Listing 4. Capturing the name of the Client class atributes

 public static void main(String[] args) {
               Client client = new Client();
               Class<Client> clazz = (Class<Client>) client.getClass();
               for(Field f : clazz.getDeclaredFields()){
                      System.out.println(f.getName());
               }
         }
  Output:
  name
  code
  birthDay
  fatherName
  motherName
  address

The getDeclaredFields() method returns an array of Field, where Field is the class used to manipulate the attributes present in the class that we are working. We can apply the same logic to the methods, as shown in Listing 5.

Listing 5. Capturing the name of the client class methods

 public static void main(String[] args) {
               Client client = new Client();
               Class<Client> clazz = (Class<Client>) client.getClass();
               for(Method m : clazz.getDeclaredMethods()){
                      System.out.println(m.getName());
               }
   
         }
   
  Output:
  getName
  setName
  getCode
  setCode
  getBirthDay
  setBirthDay
  getFatherName
  setFatherName
  getMotherName
  setMotherName
  getAddress
  setAddress

How could we create a generic method to instantiate/create any type of object, regardless of your class? Imagine that we do not know which class should instantiate, so we can not use the reserved word "new MinhaClass()". We just need to provide a method where you pass the class through MinhaClasse.class, and this method instantiation is made and the return is the desired object. Note Listing 6.

Listing 6. Creating a generic method to instantiate classes with reflection

 private static Object createNewInstance(Class clazz) {
               Constructor<?> ctor;
               try {
                      ctor = clazz.getConstructors()[0];
                      Object object = ctor.newInstance();
                      return object;
               } catch (SecurityException
                             | InstantiationException | IllegalAccessException
                             | IllegalArgumentException | InvocationTargetException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
               }
               
               return null;
         }

The createNewInstance method is responsible for returning an instance of Class, regardless of type. What we do is use the "clazz" to capture the first builder found, which is empty. After capturing this we call the newInstance() method, which returns an object of type "clazz". Some exceptions are mandatory, so we put the try-catch block and added five exceptions required or checked exceptions.

Let's see how to use the method provided in Listing 6 with the Listing 7 code.

Listing 7. Using createnewinstance

 public static void main(String[] args) {
               Client client = (Client) createNewInstance(Client.class);
   
               if (client == null) {
                      System.err.println("Ops, it wasn’t possible to create the cliente object");
               } else {
                      System.out.println("Client object created = " + client.toString());
               }
   
         }
  Output:
Client object created = Client@5f67198e

Note that at no time use "new Client()" because the method createnewinstance not know the Client class exists. He will not know it at run time. Now it becomes clearer to understand how current frameworks can "read" your class without entering a line of code on it, notice that nothing has been implemented specifically for the Client class.

Annotations

Annotations are metadata available from Java 5, to "set up" before certain features that should be made into separate files, for example, in XML.

You must use various daily annotations, such as @Override, @Deprecated, @Entity, @Table, @Column and etc. If you try to use @Override in a method that does not have a similar in the parent class, then you will see a design-time error, and this is only possible because Java uses reflection to see if there is a method with the same signature in the parent class, otherwise the @Override will not be accepted.

In this section we will create our own annotation, which will aim to annotate methods that should be displayed on the console, so understand how to create annotations. Not to confuse start writing down our methods @Show, as shown in Listing 8.

Listing 8. Noting our methods @Show

 import java.util.Date;
  public class Client {
         
         private String name;
         private int code;
         private Date birthDay;
         private String fatherName;
         private String motherName;
         private String address;
         
         @Show
         public String getName() {
               return name;
         }
         
         public void setName(String name) {
               this.name = name;
         }
         
   
         @Show
         public int getCode() {
               return code;
         }
         
         public void setCode(int code) {
               this.code = code;
         }
         
         @Show
         public Date getBirthDay() {
               return birthDay;
         }
         
         
         public void setBirthDay(Date birthDay) {
               this.birthDay = birthDay;
         }
         
         public String getFatherName() {
               return fatherName;
         }
         
         public void setFatherName(String fatherName) {
               this.fatherName = fatherName;
         }
         
         public String getMotherName() {
               return motherName;
         }
         
         public void setMotherName(String motherName) {
               this.motherName = motherName;
         }
         
   
         @Show
         public String getAddress() {
               return address;
         }
         
         public void setAddress(String address) {
               this.address = address;
         }      
   
  }

Initially you will see the following error: "Show can not be resolved to a type". This is because our record was not created and to do this follow the following code:

public @interface Show {
  }

From the moment that the Show annotation is created the error in Listing 8 will disappear and you will be able to compile the code. Java chose to use @interface as a resource for annotations, as the architects of the language preferred not to create a new word reserved only for recording, something like: public Annotation Show{}.

Now we need to define two important attributes for our annotation:

1.What kind of structure it can write down? Methods, classes, attributes, manufacturers, packages and so on? For this we use @Target (ElementType.METHOD) when we want to specify that our annotation will only serve to methods or @Taget (ElementType.FIELD) to annotate attributes, and so on.

2.The annotation is only at compile time or run? An example of this is the @Override annotation, which is only at compile time because the Java will check if that method exists in the parent class, otherwise the code or come to be compiled. Already our @Show annotation will be used only at run time, as when reading the methods of the Client class will check whether this was annotationd with @Show, otherwise ignore it. For this we will use: @Retention (RetentionPolicy.RUNTIME).

See how was our final annotation in Listing 9.

Listing 9. Complete code of @Show annotation

 import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;


  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface Show {
         
  }

Now we're ready for the last step, which is to make use of @Show annotation with reflection. Our goal will be popular the client object with some data and then pass it to a method where the values annotated with @Show will be displayed on the console. For example, the getName() show the client name and so forth, as shown in Listing 10.

Listing 10. Showing method of @Show annotation

 // Show values  only with @Show annotation
         public static void showValores(Object obj) {
               try {
                      Class clazz = obj.getClass();
                      for (Method m : clazz.getDeclaredMethods()) {
                             if (m.isAnnotationPresent(Show.class)){
                                    System.out.println(m.getName()+": "+m.invoke(obj));
                             }
                      }
               } catch (IllegalAccessException | IllegalArgumentException
                             | InvocationTargetException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
               }
         }

The showValores() method receives the object you want to manipulate. Soon after, captured the class of that object. Possession of class we captured all the methods of this object, because we know that @Show annotation can only be used in methods.

Making an iteration in the methods of the past object, we need to check whether that particular method has the @Show annotation, and to do this we use the following code:

m.isAnnotationPresent(Show.class)

The isAnnotationPresent() checks whether that particular method has the last annotation as a parameter, in our case, Show.class. If this is true, we run the method. But how do we do it?

A very interesting action Method class is the invoke(), which allows you to call a method through reflection, and it is exactly that we used to call the getName(), getCode(), etc., as shown in the following code:

System.out.println(m.getName()+": "+m.invoke(obj));

The invoke() returns an object, being the highest hierarchy of class, and we can cast for any other. This means that our method can return an integer, double, string, char, list, set, and etc.

Could understand what will happen after we call the Invoke()? Only the values marked with @Show will be displayed on the console, as well as desire.

Let's see a practical example of this in Listing 11.

Listing 11. Using showValores() method

 public static void main(String[] args) {
               Client client = new Client();
               client.setCode(1010);
               client.setBirthDay(new Date());
                client.setAddress("ABC Street, YHU nº 190");
               client.setName("John Snow");
               client.setMotherName("Mary Kay Snow");
               client.setFatherName("Terry Snow");
               
               showValores(client);
         }
   
  Output:
  getName: John Snow
  getCode: 1010
  getBirthDay: Thu Mar 12 21:04:33 BRT 2016
  getAddress: ABC Street, YHU nº 190 

Imagine the world of possibilities that opens when we learn to use the reflection, especially for those who want to work with reusability in large-scale building API's responsible for engaging in any project.

Pay attention that given our logic presented, if we write down a set() method with the @Show have an error because the set() expects parameter and we do not pass any parameters to invoke(), as shown in Listing 12.

Listing 12. Noting the wrong method

 @Show
public void setName(String name) {
	this.name = name;
}

Above annotation the setName() with @Show, and now let's run again in Listing 12 and see the result in Listing 13.

Listing 13. @Show Result

 java.lang.IllegalArgumentException: wrong number of arguments
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
         at java.lang.reflect.Method.invoke(Method.java:606)
         at ReflectionApp.showValores(ReflectionApp.java:28)
         at ReflectionApp.main(ReflectionApp.java:19)

Exactly what we expected: wrong number of arguments.

In this case, the invoke() must receive the parameter for the setName() and how is not receiving, it returns the above error. And how can we solve this?

One possible way is to check the showValores() method is the method that has the @Show annotation receives no parameters, otherwise, we display a message on the console and move to the next. Thus, even if a wrong entry has been made we will not have many problems, as shown in Listing 14.

Listing 14. Ignoring methods parameters

 // Mostra valores apenas com anotação @Show
         public static void showValores(Object obj) {
               try {
                      Class clazz = obj.getClass();
                      for (Method m : clazz.getDeclaredMethods()) {
                             if (m.isAnnotationPresent(Show.class)){
                                    if (m.getParameterTypes().length > 0){
                                          System.err.println(" "+m.getName()+" annotated with @Show wrongly, ignoring...");
                                          continue;
                                    }
                                    System.out.println(m.getName()+": "+m.invoke(obj));
                             }
                      }
               } catch (IllegalAccessException | IllegalArgumentException
                             | InvocationTargetException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
               }
         }

Add the line " if (m.getParameterTypes().length > 0)” which will check if there is at least one parameter in this method, and if this is true, a message will be displayed and the iteration will go to the next step through the "continues".

This article aimed to show the creation of a simple annotation to show specific values of an object, but by necessity had to explain the whole concept of reflection until we can get the annotations, otherwise it would not be possible. The use of annotations and reflections consequently is directly linked to construction mainly of frameworks that can work in a more general way possible, without specifically worry about the developer's business rule, but with the structure he needs.



Fabrí­cio Galdino is a software expert and has worked with IT analysis and business development for more than five years. It has extensive experience with testing, back and front-end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login