Dynamic Class Loading using Java Reflection

In this article we will discuss the concept of Java Reflection. Java Reflection is used to determine methods and attributes that will be used in a certain class at runtime.The Reflection in a nutshell, is used to determine methods and attributes that will be used in class (you do not know) at runtime. There are many uses for this type of task, we can mention for example the installation of additional plugins to our developed software.

Imagine if every time a new plugin was developed for the Eclipse , it had to be refactored to adapt to the use of this new plugin. It would be very laborious and impractical, given the amount of plugins that are developed for this IDE. The solution for this is undoubtedly the use of Reflection API. Say for example, strategic points of the system accept the installation of plugins in order to make the system extensible.

Reflection Example Listing 1 : Applying Reflection
</div>
<div>
<pre>Class unknownClass = UnknownClass.class;
for (Field attribute: unknownClass.getDeclaredFields()) {
	System.out.println (attribute.getName ());
}
Notice in the above code we do not know methods and attributes of “UnknownClass”, for this we will use the tools offered by Reflection in order to find this information at runtime. Note that the method “getDeclaredFields” can capture all the attributes of the class in question, without knowing how it was built.

Risks of Java Reflection

This feature should be used with care, always paying attention to the possible risks that can be caused by improper use:

  • Reduction of Performance: because the code that is being executed is required very often, hence will result in a reduction of performance.
  • Problems for security restriction: especially if done in an environment with specific rules.
  • Exposure of the internal structure of objects: for using this feature we have access to all methods and attributes of the given object, this can be a problem when it comes to security.

Benefits of Java Reflection

There are also the benefits that can be availed if we use the Java Reflection correctly and appropriately.

  • Ease of maintenance
  • Minimizing Errors
  • Productivity Gain
  • Standardization
  • Extensibility

Some items are pretty obvious, such as the Productivity Gain, because it is clear that we will not need to rewrite code every time we want to add new features to our system, it is obvious that it has to be ready to receive such ” Coupling “. We consider the extensibility as one of the most important points and beneficiaries of Java Reflection.

Using Java Reflection in the correct way in our system can become more complex (in terms of features). By just adding plugins without messing with any code, it is incredible and extremely powerful.

Some known examples that use the idea of reflection to make your software extensible are tools like Hibernate, Netbeans, Eclipse and among others that enable new plugins to be installed without changing the application code page . Hibernate example uses the Java Reflection to discover fields in our class in order to create the database tables (using the auto-update = ‘true’).

Let us see an example below which creates a class file with several fields and then apply Reflection.

Reflection Example Listing 2 : Defining our Class File
</div>
<div>
<pre>package net.javabeat;

public class File {
	private String name;
	private String numberOfCCP;
	private int quantityOfCCP;
	private String toHashTable;
	private boolean performCheckSum;
	private boolean converterHash;
	private boolean combineNameNumberCCP;

	public String getName() {
		return name;
	}

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

	public String getNumberOfCCP() {
		return numberOfCCP;
	}

	public void setNumberOfCCP(String numberOfCCP) {
		this.numberOfCCP = numberOfCCP;
	}

	public int getQuantityOfCCP() {
		return quantityOfCCP;
	}

	public void setQuantityOfCCP(int quantityOfCCP) {
		this.quantityOfCCP = quantityOfCCP;
	}

	public String getToHashTable() {
		return toHashTable;
	}

	public void setToHashTable(String toHashTable) {
		this.toHashTable = toHashTable;
	}

	public boolean isPerformCheckSum() {
		return performCheckSum;
	}

	public void setPerformCheckSum(boolean performCheckSum) {
		this.performCheckSum = performCheckSum;
	}

	public boolean isConverterHash() {
		return converterHash;
	}

	public void setConverterHash(boolean converterHash) {
		this.converterHash = converterHash;
	}

	public boolean isCombineNameNumberCCP() {
		return combineNameNumberCCP;
	}

	public void setCombineNameNumberCCP(boolean combineNameNumberCCP) {
		this.combineNameNumberCCP = combineNameNumberCCP;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (combineNameNumberCCP ? 1231 : 1237);
		result = prime * result + (converterHash ? 1231 : 1237);
		result = prime * result
				+ ((toHashTable == null) ? 0 : toHashTable.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result
				+ ((numberOfCCP == null) ? 0 : numberOfCCP.hashCode());
		result = prime * result + quantityOfCCP;
		result = prime * result + (performCheckSum ? 1231 : 1237);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		File other = (File) obj;
		if (combineNameNumberCCP != other.combineNameNumberCCP)
			return false;
		if (converterHash != other.converterHash)
			return false;
		if (toHashTable == null) {
			if (other.toHashTable != null)
				return false;
		} else if (!toHashTable.equals(other.toHashTable))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (numberOfCCP == null) {
			if (other.numberOfCCP != null)
				return false;
		} else if (!numberOfCCP.equals(other.numberOfCCP))
			return false;
		if (quantityOfCCP != other.quantityOfCCP)
			return false;
		if (performCheckSum != other.performCheckSum)
			return false;
		return true;
	}
}

Note that we have everything in our class: attributes, getters, setters, hashCode and equals. Now let’s work on it and use the reflection. In the code below, you can follow what is being done step by step with the code comments that are well documented.

Reflection Example Listing 3 : Showing attributes and methods with Reflection

</div>
<div>
<pre>package net.javabeat;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

	public static void main(String args[]) {

		/**
		 * We load the class file through Class.forName which enables us to Load
		 * a class given by a string that must match the Local default class.
		 * This default class is loaded in ClassLoader which is being used by the class
		 * that is running the command.
		 **/
		Object fileFromReflection = null;
		try {
			fileFromReflection = Class.forName("net.javabeat.File").newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// Retrieves the class name
		System.out.println("Class Name:"
				+ fileFromReflection.getClass().getName());

		/*
		 * The Class Method of Reflection gives us the possibility to handle All
		 * methods within the loaded object
		 */
		System.out.println("");
		System.out.println("Methods:");
		for (Method m : fileFromReflection.getClass().getMethods()) {
			System.out.println(m.getName());
		}

		/*
		 * We now capture the attributes of the class. We now have another
		 * important class that use Field class of Reflection. This allows us to
		 * Handle field / fields of our class loaded.
		 */
		System.out.println("");
		System.out.println("Attributes:");
		for (Field f : fileFromReflection.getClass().getDeclaredFields()) {
			System.out.println(f.getName());
		}

		/*
		 * Note that our approach is very simple, i.e, we are only capturing the
		 * names of methods and attributes, but you can go much further,
		 * capturing the modifiers, types, return and so on.
		 */

	}
}

OUTPUT:

Executing the above code gives the following output.

</div>
<div>
<pre>Class Name:net.javabeat.File

Methods:
equals
hashCode
getName
setName
getNumberOfCCP
setNumberOfCCP
getQuantityOfCCP
setQuantityOfCCP
getToHashTable
setToHashTable
isPerformCheckSum
setPerformCheckSum
isConverterHash
setConverterHash
isCombineNameNumberCCP
setCombineNameNumberCCP
wait
wait
wait
toString
getClass
notify
notifyAll

Attributes:
name
numberOfCCP
quantityOfCCP
toHashTable
performCheckSum
converterHash
combineNameNumberCCP

Summary

Reference Books:

Reflection is useful especially when we are thinking of extensible, hence making the system able to receive new features without requiring code modification.

Comments

comments

About Manisha Patil

Manisha S Patil, currently residing at Pune India. She is currently working as freelance writer for websites. She had earlier worked at Caritor Bangalore, TCS Bangalore and Sungard Pune. She has 5 years of experience in Java/J2EE technologies.

Speak Your Mind

*