Showing posts with label Reflection API. Show all posts
Showing posts with label Reflection API. Show all posts

Points To Remember

  • An annotation can be used as a replacement of interfaces.
  • You can make both empty/marker annotations and annotations with methods.
  • You can define the retention policy for the annotation and where the annotation can be used.

Program : Create A Custom Annotation

The following program creates a custom empty annotation.
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

public String name() default "table";
}

The above class can be used as a custom annotation with only one method name with a default value. This annotation can be applied only to the class i.e it is class level annotation and can not be applied to any member of a class.

The following program creates a custom annotation with methods defined.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
public String name() default "";
}
In the above example the annotation @Column can be applied only to the fields of a class and not at class level or method level.

@Table(name="user_table")
public class User {

@Column(name="ekiras")
private String username;
 public String password;
}
The above code represents how we can use the annotations @Table and @Column to annotate in any pojo class like the class User mentioned above.
public class RunTest {

public static void main(String args[]){
test();

}

public static void test(){
Table table = User.class.getAnnotation(Table.class);
if(table!=null){
System.out.println("Class is annotated with @Table and name="+table.name());
Field[] fields = User.class.getFields();
for(Field field : fields){
Column column = field.getAnnotation(Column.class);
if(column!=null)
System.out.println("Field "+field.getName() +" annotated with @Column name="+column.name());
else {
System.out.println("Field "+field.getName() +" is not annotated with @Column");
}
}
}
}

}
Class is annotated with @Table and name=user_table
Field username annotated with @Column name=ekiras
Field password is not annotated with @Column



Points To Remember

  • You to need to add the Reflections jar in the class path. 
  • You will not be able to load the packages other than the current package using Package.getPackages() since current class loader will not be able to reach them.

Program : Scan all packages with a Prefix

You can use Package.getPackages() approach to find all the packages that are in the current class loader. But you will not be able to get the packages that are not in the class path of the current class loader. So you need to include the jar "Reflections" to do this for you.
All the dependency to the project via pom.xml or you can add the jar in the class path of the project.

The following code will list all the packages in the project that start with the prefix in the project.

 public static Set<String> findAllPackagesStartingWith(String prefix) {
List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false), new ResourcesScanner())
.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(prefix))));
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

Set<String> packageNameSet = new TreeSet<String>();
for (Class<?> classInstance : classes) {
String packageName = classInstance.getPackage().getName();
if (packageName.startsWith(prefix)) {
packageNameSet.add(packageName);
}
}
for(String t : packageNameSet){
System.out.println(":::"+t);
}
return packageNameSet;
}

If you want the packages in the project in the form of Package class you can do
public Set<Package> findAllPackagesStartingWith(String prefix) {
List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false), new ResourcesScanner())
.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(prefix))));
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

Set<Package> packageNameSet = new TreeSet<Package>();
for (Class<?> classInstance : classes) {
if (classInstance.getPackage().getName().startsWith(prefix)) {
packageNameSet.add(classInstance.getPackage());
}
}

return packageNameSet;
}
When we run the above code in a demo java project and call the function as findAllPackagesStartingWith("java"); we will get a output like the following. The output may differ for you depending upon the packages in your project.
package = javassist
package = javassist.bytecode
package = javassist.bytecode.analysis
package = javassist.bytecode.annotation
package = javassist.bytecode.stackmap
package = javassist.compiler
package = javassist.compiler.ast
package = javassist.convert
package = javassist.expr
package = javassist.runtime
package = javassist.scopedpool
package = javassist.tools
package = javassist.tools.reflect
package = javassist.tools.rmi
package = javassist.tools.web
package = javassist.util
package = javassist.util.proxy
package = javax.annotation
package = javax.annotation.concurrent
package = javax.annotation.meta
package = javax.xml.parsers
package = javax.xml.transform
package = javax.xml.transform.dom
package = javax.xml.transform.sax
package = javax.xml.transform.stream

Points To Remember
  • We can use reflection to find all the fields available within a class.
  • We can get all the declared fields in a class by getDeclaredFields().
  • We can search for any field in a class by using getField(). It throws NoSuchFieldException if the field does not exist in the class.
Program : Get all the declared fields in a class
import java.lang.reflect.Field;


class SampleClass{

String s1 = "Class variable";
int a = 123;

}

class Test{

public static void main(String args[]){
Test obj = new Test();
try{
Class clazz = Class.forName("SampleClass");
Field feilds[] = obj.getDeclaredFields(clazz);
for(Field feild : feilds){
System.out.println(feild);
}
}catch(Exception e){
e.printStackTrace();
}

}

public Field[] getDeclaredFields(Class clazz){
return clazz.getDeclaredFields();
}

}
java.lang.String SampleClass.s1
int SampleClass.a
Program : Get a particular field declared in a class.
import java.lang.reflect.Field;

class SuperClass{
public String abc = "super class";

}

class SampleClass extends SuperClass{

public String s1 = "Class variable";
public int a = 123;

}

class Test{

public static void main(String args[]){
Test obj = new Test();
try{
Class clazz = Class.forName("SampleClass");
Field feild = obj.getField(clazz, "abc");
System.out.println(feild);
}catch(Exception e){
e.printStackTrace();
}

}

public Field getField(Class clazz, String field) throws NoSuchFieldException{
return clazz.getField(field);
}

}
public java.lang.String SuperClass.abc
We can only get the public fields declared in a class using this method. In case we try to access the private or default fields of the class, we will get a NoSuchFieldException.
Points To Remember
  • We can use Reflection API to get all methods available in a class.
  • Method class is present in java.land.reflect.Method class.
  • We can use getDeclaredMethods() to get all the declared Methods in a class.
  • We can use getMethods() to get all the methods available in a class. It also includes methods from its super classes.
Program : Get All Methods Declared in a Class
import java.lang.reflect.Method;


class SampleClass{

String s1 = "Class variable";
int a = 123;

public SampleClass(){
System.out.println("SampleClass Default Constructor");
}

public SampleClass(String str){
System.out.println("SampleClass Overloaded Constructor");
}

public void show(){
System.out.println("SampleClass Show Method");
}

public void print(){
System.out.println("SampleClass Print Method");
}

}

class Test{

public static void main(String args[]){
Test obj = new Test();
try{
Class clazz = Class.forName("SampleClass");
Method declaredMethods[] = obj.getDeclaredMethods(clazz);
for(Method method : declaredMethods){
System.out.println(method);
}
}catch(Exception e){
e.printStackTrace();
}

}

public Method[] getDeclaredMethods(Class clazz){
return clazz.getDeclaredMethods();
}



}
public void SampleClass.show()
public void SampleClass.print()
Program : Get All Declared and Inherited Methods of a Class
import java.lang.reflect.Method;


class SampleClass{

String s1 = "Class variable";
int a = 123;

public SampleClass(){
System.out.println("SampleClass Default Constructor");
}

public SampleClass(String str){
System.out.println("SampleClass Overloaded Constructor");
}

public void show(){
System.out.println("SampleClass Show Method");
}

public void print(){
System.out.println("SampleClass Print Method");
}

}

class Test{

public static void main(String args[]){
Test obj = new Test();
try{
Class clazz = Class.forName("SampleClass");
Method allMethods[] = obj.getAllMethods(clazz);
for(Method method : allMethods){
System.out.println(method);
}
}catch(Exception e){
e.printStackTrace();
}

}

public Method[] getAllMethods(Class clazz){
return clazz.getMethods();
}



}
public void SampleClass.show()
public void SampleClass.print()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
Difference between the getDeclaredMethods() and getMethods() is that getDeclaredMethods() will return all the methods that are declared within the class while getMethods() will return all the methods that are declared in the class and all the methods that this class inherits from its super classes.
Points To Remember
  • We can get the constructors declared in a class using Reflection API.
  • Constructor class is present in java.lang.reflect.Constructor class.
  • The getDeclaredConstructors() method will return an array of Constructors in a class.
Program : Get all constructors declared in a class
import java.lang.reflect.Constructor;


class SampleClass{

String s1 = "Class variable";
int a = 123;

public SampleClass(){
System.out.println("SampleClass Default Constructor");
}

public SampleClass(String str){
System.out.println("SampleClass Overloaded Constructor");
}

public void show(){
System.out.println("SampleClass Show Method");
}

public void print(){
System.out.println("SampleClass Print Method");
}

}

class Test{

public static void main(String args[]){
Test obj = new Test();
try{
Class clazz = Class.forName("SampleClass");
Constructor cc[] = obj.getConstructors(clazz);
for(Constructor constructor : cc){
System.out.println(constructor);
}
}catch(Exception e){
e.printStackTrace();
}

}

public Constructor[] getConstructors(Class clazz){
return clazz.getDeclaredConstructors();
}

}
public SampleClass()
public SampleClass(java.lang.String)
The above example shows how we can get all the constructors that are declared within a class. We first get the Class of the class and then call the getDeclaredConstructors() methods to get an array of all declared constructors.
Points To Remember
  • Reflection API is a powerful technique to find out environment of a class as well as to inspect the class itself.
  • Reflection API was introduced in Java v1.1
  • It allows user to get full information about the classes, interfaces, constructors, methods, variables etc.
  • It is available in java.lang.reflect package.
Example : Creating Object Using Reflection API
In the example below we are trying to create the object of class "A" in class "Test" using reflection api. We will first get the class of "A" by using .class and then call the newInstance() method to get the object of this class.
class A{

public A(){
System.out.println("class A constructor");
}

public void show(){
System.out.println("class A show() ");
}
public void show(String s){
System.out.println(s);
}
}

public class Test{

public static void main(String args[]){
try{

Class clazz = A.class;
A object = (A)clazz.newInstance();
object.show();
object.show("class A show(String)");

}catch(Exception e){
System.out.println("Error");

}
}

}
class A constructor
class A show()
class A show(String)
Example : Creating Object Using Class.forName()
In this example we will create the object of a class using Class.forName("").newInstance(). This will give us an object of the class we specify in .forName().
class A{

public A(){
System.out.println("class A constructor");
}

public void show(){
System.out.println("class A show() ");
}
public void show(String s){
System.out.println(s);
}
}

public class Test{

public static void main(String args[]){
try{
A object = (A)Class.forName("A").newInstance();
object.show();
object.show("class A show(String)");

}catch(Exception e){
System.out.println("Error");

}
}

}
class A constructor
class A show()
class A show(String)