Convert a String to a function call
Hi,
I'm doubting this is even possible, but I wanted to check before I gave up all hope :)
Is it possible to convert a String to an actual function call in Java?
For example if I have the following:
String functionName = "classname.myFunction()";
is there a way to actually call the function classname.myFunction(); within my program from that String?
The reason I need to do this is rather complicated, but maybe one of you will have a better solution if there is no way to convert a String to a function:
I am using a JSP form to collect data from a user. I have already created a Java Bean to do data validation of the data submitted on the form. This bean checks the data when the form is submitted. If the data is correct, the form data will be forwarded to another JSP form that processes the data and inserts it into the database. If the data is incorrect the user is sent back to the form with all of the data they already entered still filled in on the form so they can correct the problems. I accomplish this by setting the "value" of each form element on the form to call the "get" function from the form validation bean.
On the form I am creating I have a rather complex combination of form elements. One of which is a table with 5 rows that the user must fill in. The data in the far left column is just a label for each row pulled from the database and the following three columns are either text boxes or drop down menus that pull their contents from the database. I have created another Java Bean to prepare all of the data for this table (including automatically generating a unique form element "name" for each of the form elements in the table). The problem is I need to somehow (hopefully automatically) generate corresponding "get" function calls to the form validation bean for each of the form element that corresponds to my automatically generated form element names. This is where I was hoping I could convert the String into a function call to access the "get" functions of my Validation bean.
Also, If possible I'd love to have the form validation bean automatically generate the correct "get" and "set" functions for each of the form elements - sort of creating a Bean on the fly, but that's a whole other can of worms.
Any suggestions would be greatly appreciated.
Thanks in advance!
Thanks so much for your help!
I'm working on testing the approach and have run into a problem.
I've created a Java Bean called MethodCaller which includes the "invoke" fuction you provided above with one modification:
I changed:
String methodName = target.substring(posClassDelimiter + 1, posMethodDelimiter - posClassDelimiter);
to:
String methodName = target.substring(posClassDelimiter + 1, posMethodDelimiter);
Then I tried using the method as follows (The data type DataPair is a class that I created in a Java Bean. the method I try to call with your "invoke" function called getDescription() should return the "Hello World" portion of the DataPair called tester.):
DataPair tester = new DataPair();
tester.put("1","Hello World");
String target = "tester.getDescription()";
MethodCaller mc = new MethodCaller();
String result = (String)mc.invoke(target);
When I run this code I get the error message below. I'm I missunderstanding how to use the "invoke" method? It appears that it is not possible to pass a particular instance of a class to the "invoke" method. Is that correct?
THANKS!
:
java.lang.ClassNotFoundException: tester
at com.caucho.util.DynamicClassLoader.loadClass(DynamicClassLoader.java:538)
at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:141)
at teska.methodcaller.MethodCaller.invoke(MethodCaller.java:43)
at _test._Hashtable_0Vector_0Test__jsp._jspService(/home/teska/public_html/rusd/test/Hashtable_Vector_Test.jsp:120)
at com.caucho.jsp.JavaPage.service(JavaPage.java:75)
at com.caucho.jsp.Page.subservice(Page.java:506)
at com.caucho.server.http.FilterChainPage.doFilter(FilterChainPage.java:182)
at com.caucho.server.http.Invocation.service(Invocation.java:315)
at com.caucho.server.http.RunnerRequest.handleRequest(RunnerRequest.java:346)
at com.caucho.server.http.RunnerRequest.handleConnection(RunnerRequest.java:274)
at com.caucho.server.TcpConnection.run(TcpConnection.java:139)
at java.lang.Thread.run(Thread.java:534)
Hi Saish ,
Thanks again for your help! I've tried rewritig my function in my Java Bean and the code and parameters in my JSP page that call that function, but I'm wrunning into a strange error. I've looked everywhere I can think of for what is causeing the problem, but I've given up. I'm hoping you will have some more insights!
Below is my Java Bean:
================================================================================
package teska.methods;
import java.util.*;
import java.lang.reflect.*;
import teska.helper.*;
public class MethodCaller {
/*
=================================================================================================
CONSTRUCTOR - INSTANTIATE BEAN AND SET VARIABLES
=================================================================================================
*/
public MethodCaller() {
}
/*
=================================================================================================
invoke a method based on a String passing in the String and an Object that the method should be
called on
=================================================================================================
*/
public Object runMethod(String target, Object caller) throws Exception {
// Parse out the class and method names
int posClassDelimiter = target.indexOf(".");
String className = target.substring(0, posClassDelimiter);
int posMethodDelimiter = target.indexOf("(");
String methodName = target.substring(posClassDelimiter + 1, posMethodDelimiter);
// Use normal way to create the class and get a reference to the desired method
Method method = Class.forName(className).getMethod(methodName, null);
// ********** The line below is #43 - as referenced in the error message below ***************
// the same error occurs if I include the 2 lines below (converting the caller from an Object to a
// DataPair) or not.
DataPair dp = new DataPair();
dp = (DataPair)caller;
// This time use the instance of caller you passed in instead of calling newInstance() on the class.
return method.invoke(dp, null); // caller is the instance of tester
}
/*
=================================================================================================
invoke a method based on a String passing in the String and creating a new Object to run it on
=================================================================================================
*/
public Object runMethod(String target) throws Exception {
// Parse out the class and method names (I have not checked these substrings, so do some testing first)
int posClassDelimiter = target.indexOf(".");
String className = target.substring(0, posClassDelimiter);
int posMethodDelimiter = target.indexOf("(");
String methodName = target.substring(posClassDelimiter + 1, posMethodDelimiter);
// Now get the class
Class theClass = null;
theClass = Class.forName(className);
// Now get the method
Object caller = theClass.newInstance();
Method method = theClass.getMethod(methodName, null); // if you have params, see the API docs
// Return the results
return method.invoke(caller, null); // if you have params, see the API
}
} // close class
================================================================================
Below is the code in my JSP page to call the Java Bean Method:
================================================================================
<%@ page language="java" %>
<html>
<head>
<title>Test</title>
</head>
<%@ page import="java.util.*" %>
<%@ page import= "teska.helper.*" %>
<%@ page import="teska.methods.*" %>
<jsp:useBean id="DataPair" class="DataPair" scope="page" />
<jsp:useBean id="MethodCaller" class="MethodCaller" scope="page" />
<body>
CONVERT A STRING TO A FUNCTION CALL USING REFLECTION
<%
// Declare an empty DataPair (from teska.helper import) called tester
DataPair tester = new DataPair();
// Insert strings into tester
tester.put("1","Hello World");
// wrap the tester DataPair in an Object wrapper
Object caller = (Object)tester;
// create a string to represent the text of the method I want to call
String target = "DataPair.getDescription()";
// Create a new MethodCaller object (from the teska.methods import) called mc
MethodCaller mc = new MethodCaller();
// Create a string called "result" to hold the returned value from the getDescription() method called using
// the overloaded runMethod function in the MethodCaller Java Ban.
// ********** The line below is #121 - as referenced in the error message below ***************
String result = (String)mc.runMethod(target, caller);
%>
The description of the DataPair is: <%= result %>
</body>
<script language="JavaScript">
<!--
window.open = SymRealWinOpen;
//-->
</script>
</html>
================================================================================
The error message I get when I view the JSP page is:
================================================================================
java.lang.ClassNotFoundException: DataPair
at com.caucho.util.DynamicClassLoader.loadClass(DynamicClassLoader.java:538)
at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:141)
at teska.methods.MethodCaller.runMethod(MethodCaller.java:43)
at _test._Hashtable_0Vector_0Test__jsp._jspService(/home/teska/public_html/rusd/test/Hashtable_Vector_Test.jsp:121)
at com.caucho.jsp.JavaPage.service(JavaPage.java:75)
at com.caucho.jsp.Page.subservice(Page.java:506)
at com.caucho.server.http.FilterChainPage.doFilter(FilterChainPage.java:182)
at com.caucho.server.http.Invocation.service(Invocation.java:315)
at com.caucho.server.http.RunnerRequest.handleRequest(RunnerRequest.java:346)
at com.caucho.server.http.RunnerRequest.handleConnection(RunnerRequest.java:274)
at com.caucho.server.TcpConnection.run(TcpConnection.java:139)
at java.lang.Thread.run(Thread.java:534)
================================================================================
I'm not understanding why it is not able to find the DataPair class. As you can see the DataPair is imported into both the JSP page and the MethodCaller Java Bean from the teska.helper import line.
Thanks in advance!