Java - Access to non-static properties with reflection - java

I want to get my class property with string name.
I have a code like this
class Test
{
public String simple = "hello";
public void getSetting()
{
try
{
Test c = new Test();
Class cls = this.getClass();
Field field = cls.getField("simple");;
}
catch(Exception e)
{
// error
}
}
}
I get an error with this code , because my property is non-static , and when i changing my property to static , it's work fine , how can i get non-static properties with reflection?

Here's a self-contained example on how to get an instance Field through reflection.
public class Main {
// the instance field
String simple = "foo";
// some static main method
public static void main(String[] args) throws Exception {
// initializing the class as we're accessing an instance method
new Main().reflect();
}
public void reflect() {
Class<?> c = this.getClass();
try {
// using getDeclaredField for package-protected / private fields
Field field = c.getDeclaredField("simple");
// printing out field's value for this instance
System.out.println(field.get(this));
}
// TODO handle better
catch (IllegalAccessException iae) {
iae.printStackTrace();
}
catch (NoSuchFieldException n) {
n.printStackTrace();
}
}
}
Output
foo

try
{
Test c = new Test();
Class cls = c.getClass(); //Change this.getClass to c.getClass()
Field field = cls.getField("simple");;
}
The Field must be static or belong to a instance that can be get via reflection.

Related

java Object null after instance and calling inside method

can anyone help me with this issue, i'm working with java using SQLMap(ibatis).
i have 3 class which is MainConfiguration, SQLMap, DBUtility.
Main Configuration (this class is using to set an object inside SQLMap class)
public class MainConfiguration
{
public static String file = "configuration/db/SQLMapConfig.conf";
public static void main(String[] args) throws Exception
{
new MainConfiguration().loadConfiguration();
}
public static void loadConfiguration()
{
SQLMap.setMapFile(file);
List list = DBUtility.loadUsers();
}
}
SQL Map (this class is the getter and setter of and object)
public final class SQLMap
{
private static SqlMapClient sqlMap;
public static void setMapFile(String sMapFile)
{
try
{
sqlMap = SqlMapClientBuilder.buildSqlMapClient(new FileReader(sMapFile));
}
catch (Exception e)
{
throw new RuntimeException("Error initializing SqlMapClient class", e);
}
}
public static SqlMapClient getSqlMapInstance()
{
return sqlMap;
}
}
DBUtility (this class is where object instance and get object from SQLMap class)
public class DBUtility
{
// object utility
protected static SqlMapClient sqlMap = SQLMap.getSqlMapInstance();
//constructor
public DBUtility() throws Exception
{
}
public static List loadUsers()
{
//it's working
logger.info("SQLMap Get Instance = " + SQLMap.getSqlMapInstance());
//it's not working
logger.info("SQLMap Get Instance = " + sqlMap);
//code below will be error because of null sqlMap
try
{
listUser = sqlMap.queryForList("getUsers");
}
catch (Exception sqle)
{
logger.error("Error on load all user", sqle);
}
return listUser;
}
}
the logger give me this :
SQLMap Get Instance = com.ibatis.sqlmap.engine.impl.SqlMapClientImpl#76707e36
SQLMap Get Instance = null
how come the second log give me null, even i have instance the object?
Your field sqlMap is initialized when the DBUtility class is loaded, which apparently happens before SQLMap.setMapFile(file); is called. So, sqlMap points at different things: null in the static field, and an actual instance when you call the getter in loadUsers().
The problem is that DBUtility looks up the sqlMap too early. It has to wait until the file is passed to SQLMap. Change your code like this to delay the initialization of DbUtility.sqlMap:
public static void loadConfiguration()
{
SQLMap.setMapFile(file);
DBUtility.initMapClient(); // notify DBUtility
List list = DBUtility.loadUsers();
}
public class DBUtility
{
protected static SqlMapClient sqlMap; // do not initialize too early
public static void initMapClient()
{
sqlMap = SQLMap.getSqlMapInstance(); // wait for SQLMap to be ready
}
Of course, it would be simpler if you did not even have the sqlMap field in DBUtility. Just call SQLMap.getSqlMapInstance() every time you need it. This is especially important in case the instance ever changes:
listUser = SQLMap.getSqlMapInstance().queryForList("getUsers");
Read When are static variables are initialized? for a more detailed explanation of static fields.

Call a static method from abstract class

I have a class like this
parent class DevPortalTestController is absract
public class SeleniumWebDriverFactory extends DevPortalTestController {
public static RemoteWebDriver mDriver;
public SeleniumWebDriverFactory(RemoteWebDriver whichDriver)throws UnsupportedOSException, PoisonException {
super(whichDriver);
mDriver = whichDriver;
}
public List<TestContext> getBrowserTestContext(List<String> browsers)
throws Exception {
PhoenixDriver driver = null;
List<TestContext> contexts = new ArrayList<TestContext>();
logger.info("Setting browser context...");
Login login = retrieveLoginData();
for (String browser : browsers) {
// operations
Map<String, Object> browserMap = new HashMap<String, Object>();
// Populate the map with DevPortalTestController objects.
browserMap.put(MasterConstants.BROWSER, this);
.....
.....
}
return contexts;
}
public static List<TestContext> getTestContext(List<String> browsers)
throws Exception {
SeleniumWebDriverFactory instanceSel = new SeleniumWebDriverFactory(mDriver);
List<TestContext> contexts = instanceSel.getBrowserTestContext(browsers);
return contexts;
}
}
I need to call this getTestContext method in another class
for that am doing like this.Also that class is extenting another parnet class
public class DevPortalTest extends Test {
RemoteWebDriver rmDriver ;
SeleniumWebDriverFactory selFac =new SeleniumWebDriverFactory(rmDriver);
#Override
public List<TestContext> getTestContexts() {
try {
String os = System.getProperty("os.name");
if (SystemDetail.deviceIsRunningWindows()) {
return selFac.getTestContext(ZucchiniConstants.allBrowsers);
else {
throw new TestException(os + " is not supported");
}
} catch (Exception e) {
logger.error("", e);
}
return null;
}
}
But in this place
SeleniumWebDriverFactory selFac =new SeleniumWebDriverFactory(rmDriver);
I'm getting
Default constructor cannot handle exception type PoisonException
thrown by implicit super constructor. Must define an explicit
constructor
How can i call the method getTestContext inside DevPortalTest test class?
The problem is that initializer code will be placed in the "default constructor" which cannot throw any exception. Define an empty constructor that throws the exceptions to proceed.
e.g.,
DevPortalTest() throws UnsupportedOSException, PoisonException { }
You have to add the constructor to your test code:
public DevPortalTest() throws UnsupportedOSException, PoisonException {
SeleniumWebDriverFactory selFac = new SeleniumWebDriverFactory(rmDriver);
}
also, i assume you're injecting RemoteWebDriver rmDriver;
Since the method is static, you don't need an object to call it.
SeleniumWebDriverFactory.getTestContext(ZucchiniConstants.allBrowsers);
As an alternative to creating a constructor you can also do this
public class DevPortalTest extends Test {
RemoteWebDriver rmDriver ;
SeleniumWebDriverFactory selFac;
// this code block runs before constructor
{
try{
selFac = new SeleniumWebDriverFactory(rmDriver);
}catch(Exception e){
// handle exception
}
}
Static method can be accessed using class Name so there is no need to create any Object in Abstract class.

Not able to set value of instance variable of a class in Java while testing with JUnit

I am trying to test my classes using JUnits and i am facing an issue below is code.
There is a base class BaseMapper and TokenFraming which is dependent class.
The getMappedValue() from the baseclass is calling the mapStates() in the derived class.
I want to set the lineTokenizer instance variable in the TokenFraming class but it is not being set from the code.
When i debug TokenFraming the lineTokenizer is always Null and i get a Null Pointer exception when i try to access the tokenize() method.
I tried setting the value of lineTokenizer by using the setLineTokenizer() but still its not getting set. Also tried to set the value using Reflection but that also does not work. Any ideas as to what i am doing wrong here and how i can correct it. any help would be great.
Class BaseMapper {
private String fieldName;
private String fieldvalue;
// getters and setters
public static String getMappedValue(){
TokenFraming frame = new TokenFraming();
frame.mapStates(fieldName,fieldName,"validate")
}
}
Class TokenFraming {
private Tokenizer lineTokenizer = null;
public void setLineTokenizer(LineTokenizer arg) {
this.lineTokenizer = arg;
}
public String mapStates(String fieldName, String fieldName, String line) {
FieldMappedRow values = this.lineTokenizer.tokenize(line);// NullPointerException here
.......
.......
}
}
JUNit method
#Test
public void testMethods() {
TokenFraming framing = null;
try {
//using reflection to set is not working
framing = new TokenFraming();
Class<?> c1 = framing.getClass();
Field config = c1.getDeclaredField("lineTokenizer ");
config.setAccessible(true);
config.set(framing, new DefaulltToknizer());
//setting with a setter is also not working
framing.setLineTokenizer(new DefaulltToknizer());
BaseMapper mapped = new BaseMapper();
String value = mapped.getMappedValue();
} catch (Exception e) {
message = e.getMessage();
}
Assert.assertNotSame(null, message);
}
The BaseMapper class creates a new instance of TokenFraming - this is not the same instance of TokenFraming that you create in your test.
You should pass the TokenFraming object as an argument:
public static String getMappedValue(TokenFraming frame) {
frame.mapStates(fieldName,fieldName,"validate");
}

Calling a method with an argument trough reflection

I have the following code which allows me to input in the scanner the Employee getter method that I want to call and it will do it using reflection (the name of the method should not appear anywhere in the code). This works for getter methods but I now need to modify the code to do something similar for setter methods. I have been trying to figure how to do it for the past week but I have been unable. Any help would be appreciated.
Thanks.
public static void main(String[] args) {
Employee e = Employee.testEmployee(); // a sample employee
Class cls = e.getClass();
Scanner scanner = new Scanner (System.in); // to parse data the user types in
String nextCommand;
// until the user enters "quit", get the next input from the user, and if it matches
// a given command, get the desired information from the employee object
do {
System.out.print("Enter command >> ");
nextCommand = scanner.next();
Method method = null;
try{
method = cls.getMethod(nextCommand);
}
catch(NoSuchMethodException x) {
}
try{
System.out.println(method.invoke(e));
}
catch(IllegalAccessException x) {
}
catch(java.lang.reflect.InvocationTargetException x) {
}
catch(NullPointerException x) {
}
} while (! nextCommand.equals("quit"));
}
Here's a code sample that does what you want to achieve:
public class Test {
private static HashSet<Class<?>> classes = new HashSet<>();
static {
classes.add(String.class);
classes.add(Integer.class);
classes.add(GregorianCalendar.class);
}
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
X obj = new X();
obj.setField("lala");
Method method = obj.getClass().getMethod("getField", null);
System.out.println(method.invoke(obj, null));
Method setMethod = getWorkingMethod(obj);
setMethod.invoke(obj, "who let the dogs out");
System.out.println(obj.getField());
}
private static Method getWorkingMethod(Object obj) {
Method method = null;
for (Class<?> c : classes) {
try {
method = obj.getClass().getMethod("setField", c);
} catch (NoSuchMethodException | SecurityException e) {
continue;
}
if(method != null){
return method;
}
}
throw new IllegalArgumentException("No such method found!");
}
}
class X {
private String stringField;
public void setField(String s) {
stringField = s;
}
public String getField() {
return stringField;
}
}
Output:
lala
who let the dogs out
Notes:
Create a collection (I used a HashSet) that stores Class<?> objects. You will use these to iterate over the possibilities and see if a method with that argument exists.
Use a try-catch to see if the method exists (an exception is thrown when it can't find it).
This will not work for overloaded methods. If this is your scenario, you'll have to make adjustments. I expect it to be no problem though, since you said this was meant for setters (which typically don't have overloads).
You can avoid calling the getter and setter methods by directly accessing the Field through reflection.
The Field object has various get and set methods that can be used to manipulate field values.
See: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getField%28java.lang.String%29
EXAMPLE
import java.lang.reflect.Field;
public class MyObject {
private String fieldA;
public String getFieldA() {
return fieldA;
}
public void setFieldA(String fieldA) {
this.fieldA = fieldA;
}
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
MyObject myObject = new MyObject();
myObject.setFieldA("Test");
Class clazz = myObject.getClass();
Field field = clazz.getDeclaredField("fieldA");
field.setAccessible(true);
String fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.set(myObject, "Test2");
fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.setAccessible(false); //be sure to return field to private
}
}
Resolution (method or field resolution) in java slows down you execution time by 'orders of 10 or 100', hence not a smart design decision. So, resolve once at start time, cache method instance, and execute it from cache. Avoid frequent lookups using reflection.

Java reflection - invoke method inside thread

I'm just wondering if it's possible to invoke a method by reflection inside a thread. My idea is to pass to the thread constructor a method name so that is how I would like to specify what the thread should do (which method should be run). The code below is not working - I obtain an error "ClassNotFoundException".
public class Listener extends Thread {
/** Constructor */
private static Window win = new Window();
private static Class c;
private String parameter;
public Listener(String param) {
this.parameter = param;
}
public void run() {
try {
Class c = Class.forName("Listener");
Class partypes[] = new Class[1];
partypes[0] = String.class;
Method meth = c.getMethod("waitForWindowAppear", partypes);
Listener methobj = new Listener(parameter);
Object arglist[] = new Object[1];
arglist[0] = parameter;
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer) retobj;
System.out.println(retval.intValue());
} catch (Exception e) {
e.printStackTrace();
}
}
/** Method waits as a thread for window at class or title */
private static void waitForWindowAppear(String title) {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException exc) {
System.out.println("Thread waitForWindowAppear has been stoped!");
return;
}
if (win.isWindowVisible(title)) {
// System.out.println("Window found!");
return;
} else {
// System.out.println("Waiting for window!");
}
}
}
}
Do anyone have some ideas how to solve this problem?
I would say you don't have this class Listener on your Default package, therefore, what you should do is use the fully qualified name, for example:
Class c = Class.forName("foo.bar.Listener");
The ClassNotFoundException is thrown because it doesn't find Listener class, and one reason would be the incomplete name.
Additionally, you use getMethod, this will not work with private methods, please use getDeclaredMethod instead.
From documentation:
getMethod - Returns a Method object that reflects the specified public
member method of the class or interface represented by this Class
object.
getDeclaredMethod - Returns a Method object that reflects the
specified declared method of the class or interface represented by
this Class object.

Categories

Resources