Thread: Basic Knowledge - Using the Reflection API - Java

Results 1 to 6 of 6
  1. #1 Basic Knowledge - Using the Reflection API - Java 
    Registered Member
    shed's Avatar
    Join Date
    Dec 2010
    Posts
    1,835
    Thanks given
    504
    Thanks received
    576
    Rep Power
    5000
    From the Reflection (computer programming)

    In computer science, reflection is the ability of a computer program to examine (see type introspection) and modify the structure and behavior (specifically the values, meta-data, properties and functions) of the program at run time.

    Reflection can be used for observing and/or modifying program execution at run time. A reflection-oriented program component can monitor the execution of an enclosure of code and can modify itself according to a desired goal related to that enclosure. This is typically accomplished by dynamically assigning program code at run time.

    In object oriented programming languages such as Java, reflection allows inspection of classes, interfaces, fields and methods at run time without knowing the names of the interfaces, fields, methods at compile time. It also allows instances of new objects and invocation of methods.

    Reflection can also be used to adapt a given program to different situations dynamically. For example, consider an application that uses two different classes X and Y interchangeably to perform similar operations. Without reflection-oriented programming, the application might be hard-coded to call method names of class X and class Y. However, using the reflection-oriented programming paradigm, the application could be designed and written to utilize reflection in order to invoke methods in classes X and Y without hard-coding method names. Reflection-oriented programming almost always requires additional knowledge, framework, relational mapping, and object relevance in order to take advantage of more generic code execution. Hard-coding can be avoided to the extent that reflection-oriented programming is used.

    Reflection is often used as part of software testing, such as for the runtime creation/instantiation of mock objects.

    Reflection is also a key strategy for metaprogramming.

    In some object-oriented programming languages, such as C# and Java, reflection can be used to override member accessibility rules. For example, reflection makes it possible to change the value of a field marked "private" in a third-party library's class.
    This tutorial is meant to give you a basic idea of how to use reflection, not everything will be covered. Use the Java docs for further knowledge.

    Alright, let us begin.

    Fully Qualified Classes

    As reflection is used to provide runtime-access to classes, you cannot use import statements (which are only used at compile-time). Using the Class in the Reflection API, you are capable of loading any class that is fully-qualified.

    what does fully-qualified mean?

    Code:
    Class<?> cls = Class.forName("java.lang.Thread");
    This piece of code should have no trouble acquiring the Class Thread in the package java.lang, because the class is known by default to the ClassLoader. When you run a java program, all the java core classes are added to the class path for the ClassLoader to launch in and it starts looking in that path for classes. If you have a JAR file containing a class you want to access in your software, if you do not specify the class path to the jar file, the classes will be completely ignored by the ClassLoader and you will not be capable of detecting them.

    you can specify the class paths using
    Code:
    java -cp MyJar.jar; main.MyMainClass
    Using the -cp argument is basically telling the ClassLoader, "hey, i want you to search in this library for classes as well."

    Class

    Code:
    public class Person {
    
        private String name;
        private int age;
    
        public Person() {
    
        }
    
        public void setName(String name) {
    	this.name = name;
        }
    
        public String getName() {
    	return name;
        }
        
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    	
    }
    Accessing the class regularly, all you would do is:

    Code:
    Person p = new Person();
    p.setName("bob");
    System.out.print("My name is " + p.getName());
    With reflection, it's a different approach.

    Our small task is to make an object of Person, setName to bob, then print out the name using reflection. First of all, you would have to load the class.

    Code:
    Class<?> cls = Class.forName("Person");
    Now that the class is saved to cls, instantiate it.

    Code:
    Object person = cls.newInstance();
    Additional Information:
    • If you want to access an inner class, you should use the "$" Modifier between the public class and the inner class
      Code:
      Class<?> cls = Class.forName("Person$SocialLife"); //where SocialLife is an inner class.


    Now that a new instance has been acquired, we are free to start invoking methods and fields.

    method

    In Person, there are 2 public methods :
    • setName(String)
    • getName()


    After the Person class was instantiated, it's feasible to acquire the methods now.

    Code:
    Method setName = person.getClass().getDeclaredMethod("setName", String.class);
    Method getName = person.getClass().getDeclaredMethod("getName");
    Method setAge = person.getClass().getDeclaredMethod("setAge", int.class);
    Method getAge = person.getClass().getDeclaredMethod("getAge");
    setName and setAge take a second argument while getName and getAge do not. Why so? The getDeclaredMethod() method takes varargs after the first argument that will indicate that the method that is being acquired takes the specified type as a parameter. Hence why setName(String) and setAge(int) take String.class and int.class respectively as arguments.

    Methods have been declared, what's left? oh yeah, to invoke them.

    Code:
    setName.invoke(person, "bob");
    setAge.invoke(person, 17);
    Using the invoke() method, the first argument has to be the object you want this method to invoke on. Other arguments will be counted as values for the specified method's arguments. The preceding code is equivalent to the proceeding code:

    Code:
    Person person = new Person();
    person.setName("bob");
    person.setAge(17);
    After specifying the name and age of the person object, we are free to get them using the getName and getAge methods.

    Code:
    String name = (String) getName.invoke(person);
    int age = (int) getAge.invoke(person);
    Method return type is unknown at compile time, so you have to cast it yourself as shown above.

    Finally, just print the values acquired.

    Code:
    System.out.println("Name: " + name + ". Age: " + age);
    Additional Information:

    • if you have a method that returns a class such as person.getAchievements().physicalAchievements(), when invoking getAchievements, assign the value to an object.

      Code:
      Object person = Class.forName("Person").newInstance();
      Method getAchievements = person.getClass().getDeclaredMethod("getAchievements");
      Object achievements = (Object) getAchievements.invoke(person);
      Method physicalAchievements = achievements.getClass().getDeclaredMethod("physicalAchievements");
          // and so on...
    • Do not overlook Integer.class as int.class, they are DIFFERENT TYPES. If you specify Integer.class for getAge(int), you will get an exception.
    • If a method is private, you are required to grab it using getDeclaredMethod() and not getMethod(). Always use getDeclaredMethod as it will put you on the safe side.
      Code:
      public class PrivateAccessTest {
      
          public static void main(String... args) {
      	Object object = Class.forName("PrivateAccessTest").newInstance();
      
      	Method sayHiPrivatelyIncorrect = object.getClass().getMethod("sayHiPrivately"); // this is incorrect and will throw NoSuchMethodException
      	Method sayHiPrivatelyCorrect = object.getClass().getDeclaredMethod("sayHiPrivately"); // this will detect the private method
          }
      
          private void sayHiPrivately() {
      	System.out.println("Hi");
          }
      
      }


    Field

    A Field provides information about, and dynamic access to, a single field of a class or an interface. The reflected field may be a class (static) field or an instance field.

    Code:
    Object person = Class.forName("Person").newInstance();
    Field age = person.getClass().getDeclaredField("age");
    Since variable age is private, you cannot utilize it unless you make it accessible first.
    Note: if the variable is public, this step is redundant and may be avoided.
    Code:
    age.setAccessible(true);
    You're good to go now, using the get() method to obtain the value of the variable.

    Code:
    int value = (int) age.get(person);
    System.out.println("Age: " + value);
    Additional Information:

    • If you wish to get an array of class instances such as PlayerHandler.players[], you should do
      Code:
      Object playerHandler = Class.forName("server.model.players.PlayerHandler").newInstance();
      Field players = playerHandler.getClass().getField("players");
      Object[] values = (Object[]) players.get(playerHandler);
    • If a field is private, you are required to grab it using getDeclaredField() and not getField(). Always use getDeclaredField as it will put you on the safe side.
      Code:
      public class PrivateAccessTest {
      	
          private String myPrivateName = "bob";
      
          public static void main(String... args) {
      	Object object = Class.forName("PrivateAccessTest").newInstance();
      
      	Field myPrivateNameIncorrect = object.getClass().getField("myPrivateName"); // this is incorrect and will throw NoSuchFieldException
      	Field myPrivateNameCorrect = object.getClass().getDeclaredField("myPrivateName"); // this is correct and it will detect the private field
          }
      }


    Applications

    As a conclusion, the proceeding classes will demonstrate usage in actual applications such as RSPS.

    General Application
    Code:
    /*
    This Code is ready to run, put it in your favorite IDE, compile and try it out!
     */
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Scanner;
    
    public class ReflectionApplicationGeneral {
    
        public static void main(String[] args) {
        boolean runAgain = true;
        try {
            while (runAgain) {
                Scanner scanner = new Scanner(System.in);
                Object person = Class.forName("ReflectionApplicationGeneral$Person").newInstance();
    
                Method setName = person.getClass().getDeclaredMethod("setName", String.class);
                Method setAge = person.getClass().getDeclaredMethod("setAge", int.class);
                Method getName = person.getClass().getDeclaredMethod("getName");
                Method getAge = person.getClass().getDeclaredMethod("getAge");
    
                System.out.print("Enter a name: ");
                String answer = scanner.nextLine();
                setName.invoke(person, answer);
                System.out.print("Enter an age: ");
                answer = scanner.nextLine();
                setAge.invoke(person, Integer.valueOf(answer));
                System.out.println("My name is " + getName.invoke(person) + ", and I am " +
                        getAge.invoke(person) + " years old.");
    
                Field age = person.getClass().getDeclaredField("age");
                System.out.print("Make age accessible? (if you want to see what happens!) (y/n)");
                answer = scanner.nextLine();
                age.setAccessible(answer.equalsIgnoreCase("y"));
    
                Field name = person.getClass().getDeclaredField("name");
                System.out.print("Make name accessible? (if you want to see what happens!) (y/n)");
                answer = scanner.nextLine();
                name.setAccessible(answer.equalsIgnoreCase("y"));
    
                System.out.print("Age: ");
                System.out.println(age.get(person));
                System.out.print("Name: ");
                System.out.println(name.get(person));
                System.out.println("Want to go again? (y/n)");
    
                answer = scanner.nextLine();
                runAgain = answer.equalsIgnoreCase("y");
    
            }
        } catch (NoSuchMethodException e) {
            System.out.println("method does not exist!");
        } catch (IllegalAccessException e) {
            System.out.println("Access prohibited!");
        } catch (InvocationTargetException e) {
            System.out.println("Invocation error!");
        } catch (ClassNotFoundException e) {
            System.out.println("Class specified does not exist!");
        } catch (InstantiationException e) {
            System.out.println("Error instantiating.");
        } catch (NoSuchFieldException e) {
            System.out.println("No Such field!");
        }
    }
    
        static class Person {
    
            private String name;
            private int age;
    
            public Person() {
    
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public String getName() {
                 return name;
            }
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
           }
        }
    }
    RSPS Application

    Code:
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Scanner;
    
    public class PlayerMessager {
    
        public static void main(String... args) {
            try {
                Scanner scanner = new Scanner(System.in);
                System.out.print("Enter an online player name: ");
                String answer = scanner.nextLine();
    
                Object playerHandler = Class.forName("server.model.players.PlayerHandler");
                Field field = playerHandler.getClass().getDeclaredField("players");
                Object[] players = (Object[]) field.get(playerHandler);
    
                for (int i = 0; i < players.length; i++) {
                    Object c = players[i];
                    if (c != null) {
                        Field playerName = c.getClass().getDeclaredField("playerName");
                        if (playerName.get(c).toString().equalsIgnoreCase(answer)) {
                            System.out.println(answer + " is online, what do you wish to tell them ?");
                            answer = scanner.nextLine();
                            Method sendMessage = c.getClass().getDeclaredMethod("sendMessage", String.class);
                            sendMessage.invoke(c, answer);
                            System.out.println("Sent the message successfully");
                            return;
                        }
                    }
                }
                System.out.println("could not find player");
            } catch (NoSuchFieldException e) {
                System.out.println("Field not found.");
            } catch (IllegalAccessException e) {
                System.out.println("Illegal Access.");
            } catch (InvocationTargetException e) {
                System.out.println("Invocation Target Exception.");
            } catch (NoSuchMethodException e) {
                System.out.println("Method not found.");
            } catch (ClassNotFoundException e) {
                System.out.println("Class not found.");
            }
        }
    }
    Authored by Shed
    Revised by Major
    Last edited by Major; 10-17-2014 at 08:19 PM.
    "We don't submit to terror. We make the terror." - #FU2016
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Banned Basic Knowledge - Using the Reflection API - Java Market Banned


    Join Date
    Jan 2011
    Age
    26
    Posts
    3,112
    Thanks given
    1,198
    Thanks received
    1,479
    Rep Power
    0
    isn't reflection slow?
    Reply With Quote  
     

  4. #3  
    Registered Member
    shed's Avatar
    Join Date
    Dec 2010
    Posts
    1,835
    Thanks given
    504
    Thanks received
    576
    Rep Power
    5000
    Quote Originally Posted by lare96 View Post
    isn't reflection slow?
    it varies, however it's not "slow".
    Refer to this SO for more information
    "We don't submit to terror. We make the terror." - #FU2016
    Reply With Quote  
     

  5. #4  
    Donator


    Join Date
    Sep 2007
    Age
    27
    Posts
    2,426
    Thanks given
    125
    Thanks received
    505
    Rep Power
    386
    Reflection isn't slow at all (It's about 1.5x as slow as normal performance).
    It's also worth looking into the Array class. I'm not sure, but I believe after modifying an array using the Array class, you need to then set the field after it.
    Attached image
    Reply With Quote  
     

  6. Thankful user:


  7. #5  
    Registered Member

    Join Date
    Nov 2014
    Posts
    253
    Thanks given
    39
    Thanks received
    146
    Rep Power
    248
    You're missing ClassLoader (URLClassLoader) - most useful for these lads to create their own reflection client

    also a good class

    Code:
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    import util.ReflectionUtils;
    
    public abstract class Wrapper {
    	
    	protected Class<?> wrappedClass;
    	protected Object instance;
    	
    	public Object getInstance() {
    		return instance;
    	}
    	
    	public Wrapper(Class<?> clazz, Object instance) {
    		this.wrappedClass = clazz;
    		this.instance = instance;
    	}
    	
    	public Class<?> getRefClass() {
    		return wrappedClass;
    	}
    	
    	public final Object invoke(String name, Object...args) {
    		return invoke(name, false, args);
    	}
    	
    	public final Object invoke(String name, boolean wrapped, Object... args) {
    		List<Class<?>> classes = new ArrayList<Class<?>>(args.length);
    		for(Object o : args) {
    			if(!wrapped)
    				classes.add(unwrap(o.getClass()));
    			else
    				classes.add(o.getClass());
    		}
    		final Method method = ReflectionUtils.getMethod(wrappedClass, name, classes.toArray(new Class<?>[args.length]));
    		return ReflectionUtils.invoke(instance, method, args);
    	}
    	
    	public final <T> T getFieldVal(String name) {
    		Field f = getField(name);
    		Object o = null;
    		try {
    			o = f.get(instance);
    		} catch(Exception ex) {
    			ex.printStackTrace();
    			return null;
    		}
    		return (T)o;
    	}
    	
    	public final <T> T setField(String name, Object setTo) {
    		try {
    			getField(name).set(instance, setTo);
    			return getFieldVal(name);
    		} catch(Exception ex) {
    			ex.printStackTrace();
    			return null;
    		}
    	}
    	
    	public Field getField(String name) {
    		Field f = null;
    		try { f = wrappedClass.getField(name); } catch(Exception ex) { }
    		if(f == null) f = ReflectionUtils.getField(wrappedClass, name);
    		if(f == null)
    			throw new IllegalArgumentException(String.format("No such field %s in %s ", name ,wrappedClass.getSimpleName()));
    		f.setAccessible(true);
    		return f;	
    	}
    	
    	private static Class<?> unwrap(Class<?> wrapped) {
    		if(wrapped == Boolean.class) return boolean.class;
    		if(wrapped == Integer.class) return int.class;
    		if(wrapped == Long.class) return long.class;
    		if(wrapped == Short.class) return short.class;
    		if(wrapped == Byte.class) return byte.class;
    		return wrapped;
    	}
    }
    credits to a skype bud
    Reply With Quote  
     

  8. #6  
    Registered Member
    shed's Avatar
    Join Date
    Dec 2010
    Posts
    1,835
    Thanks given
    504
    Thanks received
    576
    Rep Power
    5000
    Quote Originally Posted by Intrice Joe View Post
    You're missing ClassLoader (URLClassLoader) - most useful for these lads to create their own reflection client

    also a good class

    Code:
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    import util.ReflectionUtils;
    
    public abstract class Wrapper {
    	
    	protected Class<?> wrappedClass;
    	protected Object instance;
    	
    	public Object getInstance() {
    		return instance;
    	}
    	
    	public Wrapper(Class<?> clazz, Object instance) {
    		this.wrappedClass = clazz;
    		this.instance = instance;
    	}
    	
    	public Class<?> getRefClass() {
    		return wrappedClass;
    	}
    	
    	public final Object invoke(String name, Object...args) {
    		return invoke(name, false, args);
    	}
    	
    	public final Object invoke(String name, boolean wrapped, Object... args) {
    		List<Class<?>> classes = new ArrayList<Class<?>>(args.length);
    		for(Object o : args) {
    			if(!wrapped)
    				classes.add(unwrap(o.getClass()));
    			else
    				classes.add(o.getClass());
    		}
    		final Method method = ReflectionUtils.getMethod(wrappedClass, name, classes.toArray(new Class<?>[args.length]));
    		return ReflectionUtils.invoke(instance, method, args);
    	}
    	
    	public final <T> T getFieldVal(String name) {
    		Field f = getField(name);
    		Object o = null;
    		try {
    			o = f.get(instance);
    		} catch(Exception ex) {
    			ex.printStackTrace();
    			return null;
    		}
    		return (T)o;
    	}
    	
    	public final <T> T setField(String name, Object setTo) {
    		try {
    			getField(name).set(instance, setTo);
    			return getFieldVal(name);
    		} catch(Exception ex) {
    			ex.printStackTrace();
    			return null;
    		}
    	}
    	
    	public Field getField(String name) {
    		Field f = null;
    		try { f = wrappedClass.getField(name); } catch(Exception ex) { }
    		if(f == null) f = ReflectionUtils.getField(wrappedClass, name);
    		if(f == null)
    			throw new IllegalArgumentException(String.format("No such field %s in %s ", name ,wrappedClass.getSimpleName()));
    		f.setAccessible(true);
    		return f;	
    	}
    	
    	private static Class<?> unwrap(Class<?> wrapped) {
    		if(wrapped == Boolean.class) return boolean.class;
    		if(wrapped == Integer.class) return int.class;
    		if(wrapped == Long.class) return long.class;
    		if(wrapped == Short.class) return short.class;
    		if(wrapped == Byte.class) return byte.class;
    		return wrapped;
    	}
    }
    credits to a skype bud
    This Reference is not intended in any way to be specific in it's knowledge to making reflection clients. Thanks though.
    "We don't submit to terror. We make the terror." - #FU2016
    Reply With Quote  
     

  9. Thankful user:



Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. The Basics Of Using Eclipse!
    By Mr Joopz in forum Tutorials
    Replies: 5
    Last Post: 06-01-2013, 04:29 PM
  2. how to set up and use the reflection cheat client!
    By anythinga in forum Tutorials
    Replies: 8
    Last Post: 12-20-2012, 01:01 AM
  3. Using the java convention..
    By IceCandle in forum Application Development
    Replies: 25
    Last Post: 08-02-2010, 11:41 AM
  4. The Basics Of Using Switch
    By Vegeta in forum Tutorials
    Replies: 10
    Last Post: 02-26-2009, 06:47 PM
  5. Java, from the bean up [Java tutorial]
    By Lem0ns in forum Tutorials
    Replies: 0
    Last Post: 08-13-2007, 12:30 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •