Overwrite Object properties with properties of other Object using reflection - java

Im trying to do something that might seem a bit unorthodox, however this is due to some limitations in a framework that im using.
Basically my case is this:
1: I have an object that has several fields, all with default values.
2: I have an other object that is initialized and has all values that I want to have, in the new object.
Im trying to do this with reflection, so looping over all public setMethods, finding all getMethods that seem to be matching from the other object, invoking them and invoke the other setMethod with the value over the invoked setMethod.
This is what I came up with so far:
java.lang.reflect.Method[] publicMethods1 = newlabels.getClass().getMethods();
for(int i=0; i<publicMethods1.length; i++){
if (publicMethods1[i].getName().startsWith("set")){
String setname = publicMethods1[i].getName();
String getname = "get"+setname.substring(3, setname.length());
try {
java.lang.reflect.Method getMethod = labels.getClass().getMethod(getname, null);
publicMethods1[i].invoke(newlabels, getMethod.invoke(labels, null));
} catch (NoSuchMethodException e1) {
//System.out.println("Couldnot find a method with name: "+getname);
} catch (SecurityException e1) {
//System.out.println("Security exception occured");
} catch (IllegalAccessException e1) {
//System.out.println("IllegalAccessException");
} catch (IllegalArgumentException e1) {
//System.out.println("IllegalArgumentException");
} catch (InvocationTargetException e1) {
//System.out.println("InvocationTargetException");
}
}
}
This unfortunately isn't working, its not giving errors either (unless a getter wasnt found, but ill take that).
I looked around on the internet and found somewhat similar in this method:
/**
* Only works for methods with equally named getters and setters
*
* 1. Get all declared methods of obj1 and find all setters
* 2. Get all declared methods of obj2 and find all getters
* 3. Find which setter belongs to which getter
* 4. Set the value of obj1.setter with obj2.getter
*
* #param obj1
* #param obj2
*/
public static void runAllSettersWithGetters(Object obj1, Object obj2) {
ArrayList<Method> setters = findSetters(obj1);
ArrayList<Method> getters = findGetters(obj2);
for(int s=0; s<setters.size(); s++){
String setmethodname = setters.get(s).getName();
String whattoset = setmethodname.substring(3);
for(int g=0; g<getters.size(); g++){
boolean isboolean = false;
boolean match = false;
if(getters.get(g).getReturnType().equals(Boolean.TYPE)){
isboolean = true;
}
String getmethodname = getters.get(g).getName();
String whattoget = getmethodname.substring(3);
if(whattoset.equalsIgnoreCase(whattoget)){
match = true;
}else{
//might start with is instead of get
whattoget = getmethodname.substring(2);
if(whattoset.equalsIgnoreCase(whattoget)){
match = true;
}
}
if(match){
try {
setters.get(s).invoke(obj1, getters.get(g).invoke(obj2));
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
So I tried it, because it seems better, however in the end it gives the same not working solution.
Can anyone help me with this?

Related

Java: check if a class exists and call a specific method if it exists

Is there a way to do the following? Check if a class exists (in the same package) and if it does exist, check if a particular method exists, and if so, calling it?
Say that I have class X. In some method of class X, I want to do the following:
if (class Y exists) { //Maybe use Class.forName("Y")?
if ( Y has method a(String, String) ) {
call Y.a("hello", "world");
}
}
Is such a thing possible? And is doing such a thing reasonable? Thanks.
Is such a thing possible? And is doing such a thing reasonable?
Thanks.
Of course it is possible.
If you develop a program or a library that has to discover dynamically some classes, it is a very reasonable thing.
If it is not the case, it could not be.
If your need makes sense, you should ask you an additional question : should you invoke a static or instance method ?
Here is a sample example with both solutions :
ReflectionClass that contains the logic using reflection :
import java.lang.reflect.Method;
public class ReflectionCalls {
public static void main(String[] args) {
new ReflectionCalls();
}
public ReflectionCalls() {
callMethod(true);
callMethod(false);
}
private void callMethod(boolean isInstanceMethod) {
String className = "DiscoveredClass";
String staticMethodName = "methodStatic";
String instanceMethodName = "methodInstance";
Class<?>[] formalParameters = { int.class, String.class };
Object[] effectiveParameters = new Object[] { 5, "hello" };
String packageName = getClass().getPackage().getName();
try {
Class<?> clazz = Class.forName(packageName + "." + className);
if (!isInstanceMethod) {
Method method = clazz.getMethod(staticMethodName, formalParameters);
method.invoke(null, effectiveParameters);
}
else {
Method method = clazz.getMethod(instanceMethodName, formalParameters);
Object newInstance = clazz.newInstance();
method.invoke(newInstance, effectiveParameters);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
DiscoveredClass (the class we manipulate in the example)
package reflectionexp;
public class DiscoveredClass {
public static void methodStatic(int x, String string) {
System.out.println("static method with " + x + " and " + string);
}
public void methodInstance(int x, String string) {
System.out.println("instance method with " + x + " and " + string);
}
}
Output :
instance method with 5 and hello
static method with 5 and hello
Yes, this can be done. I've created a Test class in the same Package as the current class.
import java.lang.reflect.Method;
public class Sample {
public static void main(String[] args) {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (clazz == null) {
System.out.println("class not found. Go eat some waffles and correct the name");
return;
}
Method m = null;
try {
m = clazz.getMethod("foo", null);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (m == null) {
System.out.println("method not found. Go eat some waffles and correct the name");
return;
}
Test t;
try {
t = (Test) clazz.newInstance();
m.invoke(t, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Test {
static {
System.out.println("test...");
}
public void foo() {
System.out.println("foo");
}
}
O/P :
test...
foo
You can use Class.forName:
try {
Class yourClass = Class.forName( "classname" );
Object o = yourClass.newInstance();
} catch( ClassNotFoundException e ) {
//Throw error or whatever
}
To check if a method exists you could use the NoSuchMethodError e in a try/catch
You can do this using reflection, however it isnt really practical unless you are trying to access classes that potentially will not be present at runtime or if you are trying to access private or hidden fields. Example below.
public static void reflectionDemo(){
//Here we attempt to get the common URI class
//If it is found, we attempt to get the create method
//We then invoke the create method and print the class name of the result.
try {
Class<?> uriClass = Class.forName("java.net.URI");
//getMethod(String name, Class<?>... args);
java.lang.reflect.Method create = uriClass.getMethod("create", String.class);
//The first parameter is null because this is a static method.
//invoke(Object target, Object... args);
System.out.println(create.invoke(null, "some/uri").getClass());
//Will print class java.net.URI
} catch (ClassNotFoundException e) {
// If class doesnt exist
e.printStackTrace();
} catch (NoSuchMethodException e) {
// If method doesnt exist
e.printStackTrace();
} catch (SecurityException e) {
// See Javadoc
e.printStackTrace();
} catch (IllegalAccessException e) {
// From invoke
e.printStackTrace();
} catch (IllegalArgumentException e) {
// From invoke
e.printStackTrace();
} catch (java.lang.reflect.InvocationTargetException e) {
// From invoke
e.printStackTrace();
}
}
To find whether a class exists, you can use the forName() method on Class.
To find whether a method exists, you can use the getMethod() method on Class.
Documentation here:
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String)
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)
For your class problem, you'd want to use code like:
try {
Class.forName("Y");
}
catch (ClassNotFoundException e) {
}
For your method problem, you'd want to use code like:
try {
Class.getMethod(a);
}
catch (NoSuchMethodException e) {
}
You can check if the Class exists with Class.forName("classname");
See this SO question: Check if class exists somewhere in package
If a method exists can be catched with NoSuchMethodError in your try/catch.
See this SO question: Check if method exists at Runtime in Java
try {
Object object = Class.forName("Y").newInstance();
object.a(String, String);
} catch( ClassNotFoundException | NoSuchMethodError ex) {
//do Something else
}

Can I use reflection to dynamically bind methods to my JTextFields?

I have a page with several JTextFields. All of their variable names start with txt i.e. txtCarArea, txtRopeLength,....
I have an orderObject, that has several fields and setters / getters to use them.
The textfields get filled with the values from the fields of the orderObject like this:
// Around 50 fields get filled like this
txtCarArea.setText(orderObject.getCar_area());
....
The user then can change the values.
Now I could get the values of every textfield and put it into the orderObject after the user clicks on a button like "Apply changes", but this again would mean I have to write 50 setter-uses and fire all of them, even if the user only changed a value in one field:
#Override
public void actionPerformed(ActionEvent e) {
// Again: Around 50 uses of the different setters
orderObject.setCar_area(txtCarArea.getText());
orderObject.setRope_length(txtRopeLength.getText());
orderObject.setDoughID(txtDoughID.getText());
(...)
}
This feels very bloated? I have to write and maintain those 50 calls.
Therefore I've read about reflection and tried to just use the setter-methods of the textfields that are changed and not all of them.
#Override
public void actionPerformed(ActionEvent e) {
orderObject.setCar_area(txtCarArea.getText());
Method[] methods = orderObject.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
if (methodName.startsWith("set")) {
methodName = "txt" + methodName.substring(3);
String newMethodName = methodName.replace("_", "");
Method method = null;
try {
// "setCarArea" is hardcoded by me
method = orderObject.getClass().getMethod("setCarArea", String.class);
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
try {
// How to invoke dynamically for every textfield?
method.invoke(orderObject, "1070");
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
}
}
}
But since I dont know to find the pair of orderObject-setter + JTextField where the value is, I am stuck now.
So how can I dynamically get the correct setter-methods in the orderObject to input the values from the JTextFields?

Calling a function from the value of a string Java [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I invoke a java method when given the method name as a string?
**I have looked at this : Call a function from a string array (Java or Groovy) and it didn't work for me, perhaps it is my scenario*
I have a String array with some values, and I want to be able to call a method which is one of those values, of course this can change, and I could potentially have 100's of values, so it's not feasible to use a if/else if construct, or a switch statement.
Is there any way I can call the method, as I would like, as displayed in the code below?
private String[] = {"Hit","Slap","Blop"};
private String et = "Slap";
public void Action(){
for(int i = 0; i < arr.length;i++){
if(et.equals(arr[i])){
//Call method of that name ( Slap(); )
}
}
}
public void Run(){
///
}
public void Slap(){
///
}
public void Blop(){
///
}
EDIT: My attempt to integrate reflection:
for(int i = 0; i < arr.length;i++){
if(et.equals(arr[i])){
//Call method of that name
try {
method = this.getClass().getMethod(arr[i]);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
return (String) method.invoke(this);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return "FAIL";
You will have to use reflection. Something like this:
getClass().getMethod(arr[i]).invoke(this);
You can use the ReflectionAPI to achieve this. Just get the method with this name from your desired class (if available ) and invoke it with your args, in this case null.
BUT it's a bad design and you should rethink your application flow!
here is an example:
public class HelloWorld {
public static void main(String[] args) {
HelloWorld hello = new HelloWorld();
String[] calls = { "def", "abc", "ghi" };
try {
for (String call : calls) {
Method method = HelloWorld.class.getMethod(call, null);
method.invoke(hello, null);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public void abc() {
System.out.println("abc");
}
public void def() {
System.out.println("def");
}
public void ghi() {
System.out.println("ghi");
}
}

Determine if a Method is a `RemotableViewMethod`

I am building a Widget which contains a ProgressBar. If the Widget is computing I set the visibility of that ProgressBar to VISIBLE, and to INVISIBILE if all computings stopped. There should be no Problem, because the setVisibility is documented as RemotableViewMethod. However some guys at HTC seem to forget it, (i.e on the Wildfire S), so a call to RemoteViews.setVisibility will result in a crash. For this reason I try to implement a check, if setVisibility is really callable. I have writen this Method for it:
private boolean canShowProgress(){
LogCat.d(TAG, "canShowProgress");
Class<ProgressBar> barclz = ProgressBar.class;
try {
Method method = barclz.getMethod("setVisibility", new Class[]{int.class});
Annotation[] anot = method.getDeclaredAnnotations();
return anot.length > 0;
} catch (SecurityException e) {
LogCat.stackTrace(TAG, e);
} catch (NoSuchMethodException e) {
LogCat.stackTrace(TAG, e);
}
return false;
}
This will work, but is REALLY ugly as it will return `True´ if ANY Annotiation is present. I looked, how RemoteView itself is doing the lookup and found this:
if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
throw new ActionException("view: " + klass.getName()
+ " can't use method with RemoteViews: "
+ this.methodName + "(" + param.getName() + ")");
}
But i could't do the same, because the Class RemotableViewMethod is not accsesible through the sdk. How to know if it is accesible or not?
By Writing my question I had the Idea to lookup for the class by its Name, and it worked.
So I updated my Method to the following:
private boolean canShowProgress(){
LogCat.d(TAG, "canShowProgress");
Class<ProgressBar> barclz = ProgressBar.class;
try {
Method method = barclz.getMethod("setVisibility", new Class[]{int.class});
Class c = null;
try {
c = Class.forName("android.view.RemotableViewMethod");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (this.showProgress= (c != null && method.isAnnotationPresent(c)));
} catch (SecurityException e) {
LogCat.stackTrace(TAG, e);
} catch (NoSuchMethodException e) {
LogCat.stackTrace(TAG, e);
}
return false;
}
which works flawlessly

Private member in-accessible?

So i have a java class, with 3 private fields
public class Parcel {
private String guid;
private List<String> files;
private String zipFileName;
public Parcel (List<String> files, String zipFilePath){
UUID uuid = UUID.randomUUID();
guid = uuid.toString();
zipFileName = zipFilePath + File.separator + guid + File.separator + ".zip";
if ((files != null) && (!files.isEmpty())){
this.files = files;
}
}
}
Now, I am writing JUnit test to test these private fields
public class ParcelTest {
#Test
public void parcelObject() {
String zipFilePath = "/path/to/folder";
List<String> files = new ArrayList<String>();
files.add("/path/to/folder/test1");
files.add("/path/to/folder/test2");
Parcel parcel = new Parcel(files, zipFilePath);
Class<? extends Parcel> parcelClass = parcel.getClass();
try {
Field guid = parcelClass.getDeclaredField("guid");
guid.setAccessible(true);
System.out.println(guid.get(parcel));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I am getting error when trying to access private guid field. I have tried this even after creating zero argument constructor. how should i access private members here?
EDIT
I figured it out and i have updated my response if someone else needed it.
P.S:
How can i close this question>
You are much better off testing the externally visible behaviour (behaviour, not getters and setters). If your code doesn't change behaviour, you should delete it.
(Also you might want to copy your list before stashing it in a field (and before checking validity).)
Why don't you have a public getter or setter instead of dealing with reflection?

Categories