The Magic behind most JavaEE frameworks

289 0

I’m not a big fan of godification. This is a concept I invented myself to define the act of believing that some tools were built by gods and their behavior should never be questioned.

I can’t just add a library to my project and use it for critical missions without wondering : what is going on back there?? I make the question before I even use it because that’s what allows me to find the best tools and not have faith in libraries like others do.

From now on, let’s set as title: 5 things that javaEE frameworks rely on.

Reflection

Reflection is one of the 5 things. It is the technique used to obtain details about your application types (classes, interfaces, annotations). This is mostly used to list methods of a class, its fields, the interface it implements and the list goes on.

You might be like please, a framework example of reflection use. Ok. I’ll give you one : CDI.

The Contexts and Dependencies injections API (CDI API) is a very good example of how useful reflection can be.

Lets consider a scenario with two beans, MyBean and UnknownBean:

@ApplicationScoped Class MyBean{private String name;}

Lets not get into much details about the UnknownBean, lets just assume that it has a property declared as follows:

@Inject private MyBean bean;

The propaganda of the CDI API says that,” it will automatically find and instantiate the Bean for you”. The question here is: how does it instantiate the bean? And don’t please tell me it uses reflection cause I already know that. Okay. Steps:

  1. It gets all the declared fields of the UnknownBean bean
  2. It iterates over the declared fields array
  3. It attempts to get the annotation @inject for each field
  4. For each field with the @Inject annotation:
  5. It gets the Field data type (class)
  6. It gets the default constructor of the class
  7. It invokes the constructor (constructor takes no argument) : returns an object
  8. Sets the returned object as value of the field.

All the operations listed above are only allowed by reflection. This is enough for you to make the statement

“CDI wouldn’t exist without reflection”. I support you. Thank god sun microsystems built it.

How exactly is each of that steps performed? That’s not the point of this post. This is not a java reflections tutorial. The only thing I can tell you now is: every object as a getClass() method. That method is one of your doors into reflection.

There is something you should know about CDI: It creates an object proxy for every single object instance it creates. What is that? That is our next topic.

Object Proxies

Most of the people know the proxy term from networking. It is used to define an interception layer. Object Proxies are the exactly same thing. In Java, a proxy object, is an object that intercepts method calls for a wrapped object instance. Object proxies are created based on interfaces. To be clear, lets imagine a scenario were we have

An interface with the name Readable that consists of two method declarations: void:write(String) and int:getLength() and we also have one Class named Document that implements the interface Readable. We have an instance of the Document class and we want to wrap it in a object that prevents direct access to it, allowing us for example to implement rules like : a document can only be written twice within an hour. The wrapper we are looking for is an object proxy.

I wont give you a code example here, but I will give you a tip : java.lang.reflect.Proxy is a good place to begin.

Before you even ask, the frameworks that rely on Objects Proxies, I will tell you the name of one of them: Hibernate.

If you have an entity with the name Company, this entity of yours will probably have a method getEmployees that return a collection of all Employee object instances related to the Company. During build time, Hibernate will generate a new interface named CompanyInterface that contains all the methods you declared, it will also generate a class that implements that same interface.

Why is it doing so much work? Actually it is trying to help you. Imagine if you Select all Companies on your database. This doesn’t mean you want to select all the employees related to each company, isn’t it? It Depends, I know, hibernate also does. If you tell hibernate to use Eager Loading it will automatically load all employees for each company but if you tell it to use Lazy loading it won’t. It will only load the employed if you invoke the method getEmployees, that’s why it uses object Proxy. It has to be able to intercept the invocation you make to the getEmployees method. Now it’s clear why it generates an interface for your entity classes.

Bytecode scanning and generation

Let’s stick to the hibernate example (company and employees) used on the previous topic: objects Proxies.

One of the things I told you hibernate does, is to create an interface based on your Entity methods and then create a class that implements such interface. In few words: bytecode generation is what allows hibernate to create new Classes and interfaces during build. This is achieved using libraries like cglib and javaassist. You cant be wondering what is Bytecode scanning. If so, let me answer you: it is the process of scanning bytecode. But why would hibernate scan bytecode? It has load all the entity classes mapped on persistence.xml and then collect the methods of each entity and then use that information to generate the classes and interfaces and this is not all, but helps you understand what’s the purpose of bytecode scanning. Bytecode scanning allow tools to scan information on a program without executing the program code. That is the true difference between bytecode scanning and reflection. If you want to use reflection, you have to load the source and this can cause code execution. Loading a class can cause code execution if for example the class has a static block on its body:

That’s not the only pitfall (might not be the right word) about reflection, there are other things we can mention, like for example, the fact that it happens during runtime, it creates the impossibility of creating new source files and submit them for compilation.

@Annotations processing

Annotations come up with java 5 and since then they have been helping us to avoid XML configuration files.

Annotations allow developers to develop some kind of compiler plugins designated “Annotation Processors”. Such plugins are registered using the Java Services API and they are instantiated and invoked during compilation. They have the capability of detecting elements carrying specific annotations and then generate new source files during compilation that will also get compiled and scanned in rounds. Annotation processors depend heavily on source code generation libraries (libraries that allow to compose Java files from a Java program) in order to generate new source files during compilation. As they are compiler plugins, they can emit messages and even cause compilation errors. Every Java EE API supports annotations. Most of them (I would even risk and say all) do notRead the annotations using via the “Annotation Processor” implementation, they do some scanning on jar and class files Using bytecode manipulation libraries.

CDI uses annotations to provide beans injection (@Inject, @Produces, @ApplicationScoped, etc). JPA (Hibernate) uses annotations for relation definitions (@OneToMany, @ManyToMay, etc), constraints validation (@NotNull, @Max, @Size, etc). Annotations are everywhere.I began this post speaking about godification, saying I was against it but at the end I godified the bytecode manipulation libraries. The truth is there a few things that we should simply not care about how they work and focus more on what they do.

NOTE: I didn’t invent the “godification” term, a friend of mine did. Just didn’t want to tell you yet.It is always a pleasure.THE END

(Visited 53 times, 1 visits today)

Mário Júnior

Mário Francisco Júnior is the Head Of Software Development at Vodacom Mozambique.