Why am I getting extra stuff when looping through methods? - java

Okay not sure what is going on. I am using Java Reflection and iterating and inspecting methods of a particular class. Below is the following code I am using:
public void test(){
Class useCases = Car.class;
Method[] methods = useCases.getMethods();
Integer[] numbers = {2, 5};
String[] numberStrings = {"2", "5"};
for(int i=0; i<methods.length; i++){
try {
System.out.print(methods[i].getName());
Method method = useCases.getMethod(methods[i].getName(), new Class[]{String.class, Integer.class});
Object returnV = method.invoke(new Car(), numberStrings[i], numbers[i]);
System.out.print(returnV.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Car Class:
public String getNumber(String number, Integer times){
return times == 2 ? number : null;
}
public String getNumber1(String number, Integer times){
return times == 5 ? number : null;
}
It loops through fine printing out the first two methods and the return value fine, but then it continues and prints out a wait() and not sure why and I am getting the following error:
java.lang.NoSuchMethodException: sample.Car.wait(java.lang.String,
java.lang.Integer)
Any help as to why the loop does not end with just printing and returning the values for the only two methods in that Car class.

getMethods returns all public methods available for class, including the ones inherited like wait() toString() which as you see don't accept (String, Integer) arguments, which is why
useCases.getMethod(methods[i].getName(), new Class[]{String.class, Integer.class});
is not able to find wait(String, Integer).
To get only methods declared in Car class use getDeclaredMethods instead.
BTW: instead of
System.out.print(returnV.toString() + "\n");
which will throw NullPointerException on returnV.toString() if returnV will be null use
System.out.println(returnV); // also you don't need to explicitly add `\n`,
// use println will add used by current OS line
// separator for you automatically

Every Class is implicitly extending Object, so you get all methods containing in Object too.

Related

getConstructor() return a constructor that is not implemented

I'm learning some of the reflection features in Java and I got a strange problem testing the getConstructor() function with this Class.
public class IntegerSequence {
private Integer[] elements;
private int size;
private int MAX_SIZE = 100;
public IntegerSequence() {
elements = new Integer[MAX_SIZE];
size = 0;
System.out.println("Hello Guys");
}
}
The function returns a valid constructor but the "Hello Guys" message is never printed.
Furthermore, If I delete the constructor of IntegerSequence, it also return a valid constructor and doesn't throw any exception, even if there is no one anymore in IntegerSequence class.
I read that getConstructor() only returns a constructor coded in the class and not one made automatically by Java so I'm a bit lost.
Here is the code that use the function and it's output:
public void invokeDefaultConstructor(Class c){
Constructor build = null;
try {
build = c.getConstructor();
} catch (NoSuchMethodException e) {
System.out.println(e);
e.printStackTrace();
}
System.out.println(build.toString());
System.out.println(build.getName());
}
console Output:
public generics.IntegerSequence()
generics.IntegerSequence
Do you know what could cause that kind of behaviour ?
The function return a valid constructor but the "Hello Guys" message is never printed.
That's expected, since you never call the constructor anywhere. You only get the constructor from the class.
I read that getConstructor() only return a constructor coded in the class and not one made automatically by Java
I don't know where you read that. The javadoc certainly doesn't say that.

Method.Invoke without knowing the paramaters

I am using Method.Invoke in java to dynamically call methods in another class. The only issue is that if the methods have paramaters i need to start that in the class.getDeclaredMethod("method", something.class) or else it wont see those methods. The issue with this that i don't know when calling the methods what the parameters will be. How do I get around this?
Also I have done this in C# and its easy and does not require me to state the parameters but this is in Java.
Here is the code that does the Invoke:
public void DoCommand(String msg){
System.out.println(msg);
String[] temp = msg.split(" ");
String command = temp[0];
Class c = commander.getClass();
try {
Object obj = c.newInstance();
try {
System.out.println("'" + command + "'");
Method method = c.getDeclaredMethod(command);
Object[] pars = new Object[temp.length];
for(int i = 0; i < pars.length; i++){
pars[i] = temp[i + 1];
}
if((String)pars[pars.length - 1] == null){
pars[pars.length - 1] = socket;
}
Parameter[] paramaters = method.getParameters();
Object[] endParameters = AltimitConverter.ConvertParameters(pars, paramaters);
try {
method.invoke(obj, endParameters);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {}
}catch (NoSuchMethodException e){
System.out.println(e.toString());
}
}catch (Exception e){
System.out.println(e.toString());
}
}
So how do I call different methods with different parameters without stating the parameters when getting the method.
This is the C# version that does work:
private static void DoCommand(string msg, Socket soc){
string[] temp = msg.Split (' ');
string command = temp [0];
Type type = commandObject.GetType ();
MethodBase commandFunction = type.GetMethod (command);
if (commandFunction != null) {
object[] pars = new object[temp.Length - 1];
for (int i = 0; i < pars.Length; i++) {
pars [i] = temp [i + 1];
}
if ((string)pars [pars.Length - 1] == "") {
pars [pars.Length - 1] = soc;
}
ParameterInfo[] paramaters = commandFunction.GetParameters ();
object[] endParamaters = AltimitConverter.ConvertParams (pars, paramaters);
if (commandFunction != null) {
try {
commandFunction.Invoke (commandObject, endParamaters);
} catch (Exception e) {
Debug.Log (e);
}
} else {
Debug.Log ("commandFunction is null");
}
}
}
Instances of java.lang.reflect.Method reflect specific methods. Each one is associated with a specific class, has a specific parameter list, and has a specific return type. When method overloading is in play, each of the overloaded methods will be reflected by a distinct Method object; these are not interchangeable.
If you need to account for selecting among overloaded methods, then you can do so only with reference to the number and types of the intended arguments. If you have to rely on the arguments themselves to determine matching parameter types, then you're looking at duplicating Java's method-resolution logic, which is complex.
In the event that you need only worry about looking up a non-overloaded method declared by the subject class itself (i.e. not inherited) then you can invoke getDeclaredMethods() on the Class object and scan the resulting array of Method objects for one with the correct name.
You can go a little way into overloaded methods while preserving your sanity if different overloads are distinguished by different numbers of parameters, or maybe if there are specific limits on the parameter type patterns you need to account for, but at that point you really should be asking yourself whether there's a better way. This kind of design absolutely begs for trouble.
I figured out a solution. I created a function to take the intended parameters which are strings and convert them to a data type depending on if it looks like a float, Integer, or string. then i send that into another method that gets all methods in a class and get the ones with the method name i am trying to call and then gets the one with the data types i had in the object[] returned from the first method. and then i use the method i got and the converted data types to call the method.

How to print a specific instance of an object using toString

How would I print and specific instance of an object using a toString?
So basically the user is inputing information. based on the input it will either saved in instance A or Instance B. Both instance A and B are subclasses with overriding toString methods. so the input from the user is saved in an array. How can I make it so that all the inputs that was an instance of A will print?
This is the code I currently have and it is not working.
public static void printA(ABC[] inputs)
{
for(int i = 0; i < inputs.length; i++)
{
if(inputs[i] instanceof A)
{
JOptionPane.showMessageDialog(null, inputs.toString());
}
}
}
you just need is
JOptionPane.showMessageDialog(null, inputs[i].toString());
cuz you are trying to show the array.toString() not the value you want to.
You are iterating inputs, but testing clients. This is why I prefer to use a for-each loop and I suggest you use a StringBuilder to build a single message and then display it once. Something like,
public static void printA(ABC[] inputs) {
StringBuilder sb = new StringBuilder();
for (ABC input : inputs) {
if (input instanceof A) {
sb.append(input).append(System.lineSeparator());
}
}
JOptionPane.showMessageDialog(null, sb.toString().trim());
}
Edit
The output you're getting ("LClient;#20d9896e") is because you are displaying inputs.toString(). Array doesn't override toString(), you can use Arrays.toString(Object[]) like
String msg = Arrays.toString(inputs);
But you'll get all of the items in the array. Also, make sure Client overrides toString().

java.reflection.Method.invoke(...) Not re-casting args

I am trying out Java Reflection API. I am just fetching the Method objects of any given class into a JComboBox, and on it's itemSelected, creating an interface for the parameters (and of course, a calling object.)
This works fine, no issued.
But on the invokeButton's action, I am trying to invke the selected method with given params.
Initially it said that the param count differed. I was guided by one of my friend saying that the paramVals array has references to actual values, which might be causing problem, may be due to scope. I then started creating new objects of class Object and then assigning them the values. This worked for param count. But now the problem is that the parameters are not type cast properly. Even a String typecast to Object (as it has to be an array of Objects) is not being cast back to String.
The doc says that the invoke method will cast them on it's own and if cast fails, will throw an IllegalArgumentException.
I am not getting what is causing the call of invoke method fails...
Here is the code for the frame:
package nttraining.abhay.reflectiondemo;
//imports go here
public class ReflectionFrame
extends JFrame
implements ActionListener, ItemListener{
JComboBox methods;
JButton invokeButton;
public ReflectionFrame(String title) throws HeadlessException {
super(title);
//Layout components
//adding methods of class String to a combo
Class<String> c = String.class;
Method ml[] = c.getMethods();
for(Method m : ml){
methods.addItem(m);
}
invokeButton.addActionListener(this);
methods.addItemListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(invokeButton)){
Method selected = (Method) methods.getSelectedItem();
Class paramtypes[] = selected.getParameterTypes();
Object paramVals[] = new Object[paramtypes.length];
System.out.println("Method : " + selected.toString());
for(int i=0; i<paramtypes.length; i++){
Object obj = new Object();
obj = paramtypes[i].cast(params[i].getText());
paramVals[i] = obj;
System.out.println("Added " + paramtypes[i].cast(params[i].getText()).toString() + " to params");
}
try {
result.setText(selected.invoke(object.getText(), params).toString());
} catch (Exception ex) {
System.out.println(ex.getClass().getName() + ": " + ex.getMessage());
}
}
}
#Override
public void itemStateChanged(ItemEvent e) {
Method selected = (Method) methods.getSelectedItem();
if(selected==null)
return;
Class paramtypes[] = selected.getParameterTypes();
int paramCount = paramtypes.length;
object = new JTextField();
paramNames = new JLabel[paramCount];
params = new JTextField[paramCount];
panel.removeAll();
panel.setLayout(new GridLayout(paramCount+1, 2));
panel.add(new JLabel("Calling object"));
panel.add(object);
for(int i=0; i<paramCount; i++){
paramNames[i] = (JLabel) panel.add(new JLabel(paramtypes[i].getName()));
params[i] = (JTextField) panel.add(new JTextField());
}
invalidate();
validate();
}
}
A problem I found is in this line:
obj = paramtypes[i].cast(params[i].getText());
cast does not convert objects, it only verfies that the given object is of a certain class. Since you always provide a String.class as parameter (via .getText()), this will fail for anything other then a String type parameter. Even Integer.class to primitive int will fail.
Below a piece of code that demonstrates the cast problem.
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class Q21642768 {
public static void main(String[] args) {
try {
// Calls String.indexOf(str, fromIndex) via reflection.
callStringMethod("Hello reflection world", "reflection", 1);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void callStringMethod(String s, String subString, int startIndex) throws Exception {
Class<String> c = String.class;
Method ma[] = c.getMethods();
Method indexOfSub = null;
Class<?>[] indexOfSubPTypes = null;
List<Method> stringMethods = new ArrayList<Method>();
List<Type[]> stringMethodsPTypes = new ArrayList<Type[]>();
for (Method m: ma) {
stringMethods.add(m);
System.out.print(m.getName() + ": ");
Class<?>[] mptypes = m.getParameterTypes();
stringMethodsPTypes.add(mptypes);
boolean first = true;
for (Type t : mptypes) {
if (first) {
first = false;
} else {
System.out.print(", ");
}
System.out.print(t.toString());
}
if ("indexOf".equals(m.getName())
&& mptypes.length == 2
&& mptypes[0].equals(String.class)
&& mptypes[1].equals(int.class)) {
indexOfSub = m;
indexOfSubPTypes = mptypes;
System.out.println(" <-- ");
} else {
System.out.println();
}
}
if (indexOfSub == null) {
System.out.println("target method not found");
return;
}
Object[] pValues = new Object[2];
pValues[0] = indexOfSubPTypes[0].cast(subString);
// Fails:
// pValues[1] = indexOfSubPTypes[1].cast(startIndex);
// pValues[1] = indexOfSubPTypes[1].cast(startIndex + "");
pValues[1] = startIndex;
Object result = indexOfSub.invoke(s, pValues);
System.out.println("Result: " + result);
}
}
The problem is that all your parameter values are String objects, since you get them with JTextField.getText(). String is the runtime type of these values, whereas the type of the method parameters will generally be different, and this is what matters.
To successfully invoke the method, you will first need to convert each value to the proper type specified in the paramTypes array. Neither cast() nor invoke() are going to do that for you. This means you must find a way to do the conversion from a String, basically deserializing from a String value into an object of the proper class, and that may not always be possible or too complex to do. At this point, I think you can start to imagine the complexity of what you are trying to do. This is very far from trivial. Remember that each parameter value will generally not be a simple value, but rather a full object graph, that's where the complexity is.
For example, if the type of a method parameter is an interface, how will you know which concrete implementation to instantiate? If you do find a concrete class implementing it - and that may not always be possible - how will you create instances of that class? Here you're entering a domain covered by serialization frameworks in Java. There are quite a few of these frameworks that are open source and you might want to take a look at some of them. You will find a comprenhesive list of such fraleworks here.
A few years ago, I worked on a related project, where I had to provide a Swing GUI to enable end-users to create objects of arbitrary types, used as input for a rule engine. What I came up with was a JTree with multiple roots, associated with a property sheet (i.e. a JTable with 2 columns), where the tree leaves were either simple types (primitives, primitive wrappers, Date, etc.) or object references. Each reference would point to a specific tree root representing the actual object to be later instantiated. I don't remember exactly how long it took, just that it took several months to get it tested and working.
So, I don't want to crush your hopes, but you should be aware that it's going to take a huge amount of work to do this.

Printing out a sorted array by calling a method in another class that refers to another method Java Eclipse

I am having trouble using methods in another class. I have to call a method that calls another method to sort an array of strings with a bubble-sort.
the code:
/**
* My pride and joy, the bubble sort.
* #return
*/
public void BubbleSort(){
boolean run = true;
String temp;
while (run)
{
run = false;
for(int i = 0; i <stringArray.length - 1; i++)
{
if(stringArray[i].compareToIgnoreCase( stringArray[i+1]) > 0)
{
temp = stringArray[i];
stringArray[i] = stringArray[i+1];
stringArray[i+1] = temp;
run = true;
}// end of if
}// end of for
}// end of while
System.out.println(stringArray);
}// end of BubbleSort
public void PrintSortedString(){
BubbleSort();
}
those are the two methods.
when calling it from the driver class ( note the methods are in another class )
i call it like so
stringUtility.PrintSortedString();
The input is ::
Please enter names:
z
a
Your names:
[z, a]
[Ljava.lang.String;#4efe03b3 // this is where it should priont [a,z]
what did i do wrong?
What you are seeing
[Ljava.lang.String;#4efe03b3
is the result of
System.out.println(stringArray);
which internally calls stringArray.toString() and prints the result of that.
This behavior applies to all Objects. If you want custom string message, you need to have your class implement a custom toString() method instead of relying on Object#toString(). Since you can't change the String[] class, you need to iterate over the elements yourself.
Alternatively, you can rely on the Arrays class that is part of the JDK
System.out.println(Arrays.toString(stringArray));
Instead of
System.out.println(stringArray);
Try using...
System.out.println(Arrays.toString(stringArray));
The first is printing information about the array, the second is printing the content...
Updated
IF you want the methods to return the result of the sort operation, then you need to define the methods to do so...
public String[] BubbleSort(){
/*...*/
return stringArray;
}// end of BubbleSort
public String[] PrintSortedString(){
return BubbleSort();
}
This would then allow you to use System.out.println(Arrays.toString(stringUtility.PrintSortedString())
You should also take the time to read through Code Conventions for the Java Programming Language

Categories

Resources