How useful are Java Annotations?

Asked

Viewed 2,459 times

16

When I first studied Java, when I saw about Annotations I only saw that they are useful for generating metadata, but I didn’t see anything that influenced the behavior of the program. Basically, I only saw Annotations to mark authors of classes, for what class was made, etc...

But reading relevant Java code, I’ve seen many Annotations with uses I don’t know, here’s an example of a Hello World using Spring:

http://projects.spring.io/spring-framework/#Quick-start

From what I’ve been researching, if well-used Annotations can even be more flexible than C/C preprocessors++!

What are the general utilities of Annotations in Java?

  • 2

    I think a fundamental property of Annotations is to function as configuration providers (as well as XML files) but whose data can be validated at compile time, which makes them more error-resistant.

  • I like to define Annotations as semantic reviews available in Runtime.

3 answers

13


The most basic concept is: annotations are metadata.

It is additional data that you relate to classes, methods, attributes, parameters and variables.

Data can be used in time of compilation and implementation, as defined in the annotation.

Preprocessing during the build

At compile time, annotations can serve, for example, to generate additional code or even to modify bytecode class.

Compile time annotations are removed in bytecode and are not available at runtime.

Let’s look at some ideas about what you can do with this.

Code generators and manipulators

For example, Hibernate can add methods Wrappers to getters class originals to be able to load the data in mode Lazy. Did I speak Greek? It means that if you have the entities Cliente and Conta and calls a method cliente.getConta(), in fact will call a substitute method generated by Hibernate which, in case the account has not already been read from the database, will make a SELECT and create the object conta with the respective data, then returning the loaded value.

Another example of preprocessing is the design Lombok. It is able to generate the most common routines used in Pojos, such as getters, setters, toString() and hashcode(). See an example, see what the annotation @Data is able to:

@Data(staticConstructor="of")
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
}

The above code is equivalent to the following:

public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;

    private Company(final Person founder) {
        this.founder = founder;
    }

    public static Company of(final Person founder) {
        return new Company(founder);
    }

    public Person getFounder() {
        return founder;
    }

    public String getName() {
        return name;
    }

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

    public List<Person> getEmployees() {
        return employees;
    }

    public void setEmployees(final List<Person> employees) {
        this.employees = employees;
    }

    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        final Company other = (Company)o;
        if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
        return true;
    }

    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
        return result;
    }

    @java.lang.Override
    public java.lang.String toString() {
        return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
    }
}

Developer help

In addition, annotations can be used for certain validation types in the build. Take for example the annotation @Override. It defines that a subclass method is overriding a superclass method. Apparently that doesn’t help anything... until someone changes the method signature in the superclass. If someone changes the method in the superclass their subclass method would become a different method. In this case, the compiler will warn that your method with @Override is not overwriting anything else! This helps a lot to detect problems, for example when updating a library.

The sky is the limit

Other tools generate annotation-based configuration files to improve runtime performance.

Anyway, you can even make your annotation processor to run in the compilation of a program and generate whatever you want, just use the API APT (Annotation Processing Tool), available from Java. See a article on the subject (in English).

Inspection at execution time

Already annotations that are kept at runtime can be used by libraries and frameworks to identify the elements and perform additional annotations.

Auto-setup

In the case of Spring, for example, you should have seen that you can annotate the class as follows:

@Component
public class MessagePrinter { ... }

What is the magic here? When Spring is started through the Listener in his web.xml, it will read all classes within the configured package(s) (s) and add to the list of managed components whenever it finds an annotation like this.

Then you no longer need those gigantic Xmls that needed updating whenever you changed a package class or renamed it.

For more details about Spring, read my article What annotations to use for Spring 3 components.

Injection of Dependencies

Also, a note like @Autowired allows you to specify to Spring that that attribute must be filled with some component of that type. Example:

@Autowired ClienteDAO clienteDAO;

Done. No XML, no freshness. If there is a class ClienteDAO with a Spring annotation, it will automatically create an instance of it and assign there!

Automatic formatting

Many frameworks do the magic of automatically sending and recovering data from HTML forms, databases, files, etc. This is pretty cool, but how to specify the format of the data? Remembering that, for example, a date attribute may have different representations in the same data set.

For example, in JPA it is possible to specify whether the field with a Date should save only the date or time as well:

@Temporal(TemporalType.DATE)
@Column(name="CAMPO_DATA")
public Date getData()

Without it, you would have to write code or configuration in a file.

In Spring, you can use the annotation @DateTimeFormat to define what the date format is when it is converted to and from a String. So Spring can automatically receive the submitted data from an HTML form and convert it properly to the class types.

To infinity and beyond

Again, the limit on the use of runtime annotations is proportional to the developer’s creativity.

Considerations

The greatest care that every developer needs in my experience is to pay attention to the fact that the annotations are "static". This means that if a given annotated element can have a function at one time and another function at another time, it may be the case to use an external configuration.

Just to quote an example, if you used annotations to configure Dependency Injection with @Autorired and then decided to change the injected object by a subclass, will need to recompile the code by adding a @Qualifier. With the XML configuration, you wouldn’t need it. So, there are some cases where XML configuration gives greater flexibility for managing the application outside the development environment.

Anyway, annotations are an extremely powerful and flexible feature of the Java platform. They are metadata that can be read by frameworks and libraries rather than configuration via XML and imperative programming.

2

Annotations is a powerful tool, and its greatest power is to "configure" objects without the need to know the content and formation of the class.

I will use the classic example in explanation of Annotation (at least I always use this).

When we use Jtable we have to set up a tableModel, the default is horrible so we usually create one for each table we will present, right?

With Annotations we can create a tableModel configurator without the need to know during its creation, fields, objects or things that we need to put in it.

So we created a tableModelGeneric that through Reflection it will search in a class indicated what it should consider as columns, even size of fields, formatting, colors, etc.

Ex.

I created my class

Classe {

  private int ID;
  @TableLineCor(GREEN)
  @Coluna(Nome='Nome')
  private String Nome;

  @Coluna(Nome='Data de Nascimento')
  private Date Data;

//gets and sets.

}

So what happened here, when your tableModelGenerico receive as parameter this class and through Reflection it read already know that you will receive a list of objects of this class, where the line has to be green, which will have a column called Name that will receive the data of the property Name and which will have another column called Date of Birth and which will receive the data of the property Date.

So in this way, the Annotations have allowed you to create something very generic that won’t need to be rewritten when something changes in the scenario.

I believe this is one of the most important functions of the Annotations.

  • Just a comment about what I put, colors was just an example because thinking well would not work exaaaatamente that way, because who defines the part colors is a Handle in Jtable and not in Model.

1

Just to complement the other answers, I think I can give a good practical example that helps you understand some of the things explained above:

As we already know, one of the utilities of annotations is to help decrease some settings. The example that comes to mind was when the specification of the Servlets was changed with the release of Java EE 6 (JSF315). Before version 3.0, it was all mapped within web.xml, and in the new specification, with just one annotation, everything is solved internally.

3.0

@WebServlet(value="/oiMundo")
public class OiMundo extends HttpServlet {
        PrintWriter out = response.getWriter();

2.5

<servlet>
   <display-name>Servlet1</display-name>
   <servlet-name>Servlet1</servlet-name>
   <servlet-class>test.Servlet1</servlet-class>
   <init-param>
     <param-name>sleep-time-in-seconds</param-name>
     <param-value>10</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
   <servlet-name>Servlet1</servlet-name>
   <url-pattern>/Servlet1</url-pattern>
 </servlet-mapping>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.