NosuchMethodException when I try to create an object using reflexion [duplicate] - java

I have a method in my test framework that creates an instance of a class, depending on the parameters passed in:
public void test(Object... constructorArgs) throws Exception {
Constructor<T> con;
if (constructorArgs.length > 0) {
Class<?>[] parameterTypes = new Class<?>[constructorArgs.length];
for (int i = 0; i < constructorArgs.length; i++) {
parameterTypes[i] = constructorArgs[i].getClass();
}
con = clazz.getConstructor(parameterTypes);
} else {
con = clazz.getConstructor();
}
}
The problem is, this doesn't work if the constructor has primitive types, as follows:
public Range(String name, int lowerBound, int upperBound) { ... }
.test("a", 1, 3);
Results in:
java.lang.NoSuchMethodException: Range.<init>(java.lang.String, java.lang.Integer, java.lang.Integer)
The primitive ints are auto-boxed in to object versions, but how do I get them back for calling the constructor?

Use Integer.TYPE instead of Integer.class.
As per the Javadocs, this is "The Class instance representing the primitive type int."
You can also use int.class. It's a shortcut for Integer.TYPE. Not only classes, even for primitive types you can say type.class in Java.

To reference primitive types use, for example:
Integer.TYPE;
You will need to know which arguments passed into your method are primitive values. You can do this with:
object.getClass().isPrimitive()

Since the primitive types are autoboxed, the getConstructor(java.lang.Class<?>... parameterTypes) call will fail. You will need to manually loop through the available constructors. If all types match then you're fine. If some types do not match, but the required type is a primitive AND the available type is the corresponding wrapper class, then you can use that constructor. See bellow:
static <C> Constructor<C> getAppropriateConstructor(Class<C> c, Object[] initArgs){
if(initArgs == null)
initArgs = new Object[0];
for(Constructor con : c.getDeclaredConstructors()){
Class[] types = con.getParameterTypes();
if(types.length!=initArgs.length)
continue;
boolean match = true;
for(int i = 0; i < types.length; i++){
Class need = types[i], got = initArgs[i].getClass();
if(!need.isAssignableFrom(got)){
if(need.isPrimitive()){
match = (int.class.equals(need) && Integer.class.equals(got))
|| (long.class.equals(need) && Long.class.equals(got))
|| (char.class.equals(need) && Character.class.equals(got))
|| (short.class.equals(need) && Short.class.equals(got))
|| (boolean.class.equals(need) && Boolean.class.equals(got))
|| (byte.class.equals(need) && Byte.class.equals(got));
}else{
match = false;
}
}
if(!match)
break;
}
if(match)
return con;
}
throw new IllegalArgumentException("Cannot find an appropriate constructor for class " + c + " and arguments " + Arrays.toString(initArgs));
}

you can write
int[].class.getComponentType()
or
Integer.TYPE
or
int.class

If primitive int value is autoboxed into Integer object, it's not primitive anymore. You can't tell from Integer instance whether it was int at some point.
I would suggest passing two arrays into test method: one with types and another with values. It'll also remove ambiguity if you have a constructor MyClass(Object) and pass string value (getConstructor would be looking for String constructor).
Also, you can't tell expected parameter type if parameter value is null.

To actually check if a type is a primitive or it's wrapper use:
ClassUtils.isPrimitiveOrWrapper(memberClazz)
In the case you want to check if it's a specific type take a look at this:
https://stackoverflow.com/a/27400967/2739334
In any case #Andrzej Doyle was completely right!

Related

Compare an Object to a primitive type

I'd like to perform a safety check for my getClass().getField(...).set(...) where the value I am setting should match the type of that field, (int x = 1 should only allow Integers to be set). The problem is, I'm having a hard time finding ways to compare the two. Currently this is the code:
int foo = 14;
Field field = getClass().getDeclaredField("foo");
Object source = this;
// make the field accessible...
public void safeSet(Object newValue) throws IllegalAccessException {
// compare the field.getType() to the newValue type
field.set(source, newValue);
}
I've tried a lot of things, and searched around the web for quite a bit, but cannot find an answer which solely focuses on this usage of it. I've tried things like field.getType().getClass().equals(newValue.getClass()), field.getType().equals(newValue), and more, and they do not work. How can I reasonably compare a primitive field.getType() to an Object value passed in, or, how would I, in this case, compare an int, to an Integer?
Your friend is Class.isAssignableFrom()
Because you want to assign a value to a field, this is the built-in solution to do that.
if (getClass().getDeclaredField("foo").getType().isAssignableFrom(newValue.getClass())) {
....
}
It works for primitive types, too.
Step 1 :
Check field.isPrimitive(). If it returns true then it's a primitive type. and proceed to step 3.
Step 2:
If it's not primitive then you can directly check
field.getType() == newValue.getClass() and then set the value
Step 3:
if it's primitive then you need to have a static map
public final static Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
static {
map.put(boolean.class, Boolean.class);
map.put(byte.class, Byte.class);
map.put(short.class, Short.class);
map.put(char.class, Character.class);
map.put(int.class, Integer.class);
map.put(long.class, Long.class);
map.put(float.class, Float.class);
map.put(double.class, Double.class);
}
Class<?> clazz = map.get(field.getType());
then check clazz == newValue.getClass() and then set the variable.

Can method return more than one type

I am new to Java and trying to understand the below code:
int someMethod() {
return (true ? null : 0);
}
The method's return type is int, but it can return both null and int, is this correct behavior in Java? Can a Java method return more than one type? This may sound silly for those who are experienced, but I have just took my first step in Java.
A method cannot return more than one type.
The signature of a method contains the return type or void if the method doesn't return anything. Since it must be defined in the method signature, you must return something of that type.
The code
return (true ? null : 0);
is a shorthand if-else statement, or conditional ternary expression, and can be rewritten to this:
if (true) {
return null;
}
else {
return 0;
}
The above code, however, won't compile since one cannot return null if the return type is the primitive type int. The above code will compile, because the JVM will try to convert null to an int, due to auto-unboxing. At runtime, it will throw a NullPointerException, as pointed out by Eran.
In order to 'return multiple types', you could do the following:
public class BooleanOrInt {
private boolean isInteger; // Whether value is boolean or int
private boolean b;
private int i;
public BooleanOrInt(boolean b) {
this.b = b;
this.isInteger = false;
}
public BooleanOrInt(int i) {
this.i = i;
this.isInteger = true;
}
public boolean isInteger() {
return this.isInteger;
}
}
And then your code should be as follows:
BooleanOrInt methodOfA() {
if (someCondition) {
return new BooleanOrInt(theBooleanYouWant);
}
else {
return new BooleanOrInt(theIntegerYouWant);
}
}
It's a conditional ternary expression, which means the method returns one of the two values following the ?, depending on the evaluation of the condition he appears prior to ? (which in your case always returns true).
The type of the expression (true ? null : 0) is Integer, since that's the common type for null and 0.
Your code will throw a NullPointerException, since when you return a null Integer in a method whose return type is int, the JVM attempts to convert the Integer to int and fails.
In order to fix this code, you'll have to change the return type to Integer (which is the reference type that serves as a wrapper for the int primitive type) :
Integer methodOfA()
{
return (true ? null : 0);
}
Java method cannot return more than one type in the form you are suggesting. However, it can return any number of sub-types. In your case, int is a primitive type and it cannot have sub-types. Here you cannot return null since null can only be returned by methods whose return type is an object. For primitives you have to specify some values (0 in your case).

getClass() not working?

public int compareTo(Object a) {
int Output = 0;
if(this.equals(a))
Output = 0;
if(a instanceof this.getClass()) {
if(this._numDec > ((this.getClass())a)._numDec)
Output = 1;
if(this._numDec < ((this.getClass())a)._numDec)
Output = -1;
}
return Output;
}
Hello. My CS instructor told our class to create a function that would determine which of the two values would be larger, outputting 1 if the former is larger, 0 if they are equal, and -1 if the former is smaller. The this.getClass() was originally a Hexadecimal class for converting Hexadecimal values into _numDec. However, I get errors when I try to use this.getClass(). Can somebody help?
Write out the exact class name explicitly.
if (a instanceof Hexadecimal) {
if (this._numDec > ((Hexadecimal) a)._numDec)
Output = 1;
if (this._numDec < ((Hexadecimal) a)._numDec)
Output = -1;
}
By the way, if a is not a Hexadecimal object then your method is going to return 0. It should return non-zero.
You are not having problems because your call to getClass() isn't working, you are having problems because you are using incorrect casting syntax. The correct syntax is of the form:
<type> target_var = (<type>) source_var;
Where <type> is expected to be an actual Java type (primitive or object). Valid Java primitive types are (int, float, long, double, char, boolean ...). Valid object types are specified by their fully qualified name, or simple name if the type is imported. For example (String, Serializable, Object, JFrame ...).
In your code, this line:
if(this._numDec > ((this.getClass())a)._numDec)
Will not compile because you are specifying the casting to be this.getClass(), which is a dynamic expression, not a valid type.
There are several ways to accomplish your real goal, which is too determine if the supplied object is of a type that you can compare to the current object, and then to perform the comparison. Here's one such way:
if(a instanceof Binary)) {
if(this.getNumDec() > ((Binary)a).getNumDec())
Output = 1;
else
Output = -1;
} else if(a instanceof Hexadecimal) {
if(this.getNumDec() > ((Hexadecimal)a).getNumDec())
Output = 1;
else
Output = -1;
}
Note that I have replaced the use of direct property access with accessor methods.

What is .intValue() in Java?

What is the difference between them?
l is an arraylist of Integer type.
version 1:
int[] a = new int[l.size()];
for (int i = 0; i < l.size(); i++) {
a[i] = l.get(i);
}
return a;
version 2:
int[] a = new int[l.size()];
for (int i = 0; i < l.size(); i++) {
a[i] = l.get(i).intValue();
}
return a;
l.get(i); will return Integer and then calling intValue(); on it will return the integer as type int.
Converting an int to Integer is called boxing.
Converting an Integer to int is called unboxing
And so on for conversion between other primitive types and their corresponding Wrapper classes.
Since java 5, it will automatically do the required conversions for you(autoboxing), so there is no difference in your examples if you are working with Java 5 or later. The only thing you have to look after is if an Integer is null, and you directly assign it to int then it will throw NullPointerException.
Prior to java 5, the programmer himself had to do boxing/unboxing.
As you noticed, intValue is not of much use when you already know you have an Integer. However, this method is not declared in Integer, but in the general Number class. In a situation where all you know is that you have some Number, you'll realize the utility of that method.
The Object returned by l.get(i) is an instance of the Integer class.
intValue() is a instance method of the Integer class that returns a primitive int.
See Java reference doc...
http://docs.oracle.com/javase/6/docs/api/java/lang/Integer.html#intValue()
Java support two types of structures first are primitives, second are Objects.
Method that you are asking, is used to retrieve value from Object to primitive.
All java types that represent number extend class Number. This methods are in someway deprecated if you use same primitive and object type since [autoboxing] was implemented in Java 1.5.
int - primitive
Integer - object
Before Java 1.5 we was force to write
int i = integer.intValue();
since Java 1.5 we can write
int i = integer;
Those methods are also used when we need to change our type from Integer to long
long l = integer.longValue();
Consider this example:
Integer i = new Integer(10);
Integer j = new Integer(10);
if (!(i == j)) {
System.out.println("Surprise, doesn't match!");
}
if (i.intValue() == j.intValue()) {
System.out.println("Cool, matches now!");
}
which prints
Surprise, doesn't match!
Cool, matches now!
That proves that intValue() is of great relevance. More so because Java does not allow to store primitive types directly into the containers, and very often we need to compare the values stored in them. For example:
oneStack.peek() == anotherStack.peek()
doesn't work the way we usually expects it to work, while the below statement does the job, much like a workaround:
oneStack.peek().intValue() == anotherStack.peek().intValue()
get(i) will return Integer object and will get its value when you call intValue().In first case, automatically auto-unboxing happens.
They are exactly the same. As other posters have mentioned, you can put either the Integer object or the int primitive into the array. In the first case, the compiler will automatically convert the Integer object into a primitive. This is called auto-boxing.
It's just a convenience method for getting primitive value from object of Number: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Number.html
Consider the code:
Integer integerValue = Integer.valueOf(123);
float floatValue = integerValue.floatValue();
The last line is a convenient method to do:
float floatValue = (float)(int)integerValue;
Since any numeric type in Java can be explicitly cast to any other primitive numeric type, Number class implements all these conversions. As usual, some of them don't make much sense:
Integer integerValue = Integer.valueOf(123);
int intValue = integerValue.intValue();
int intValue2 = (int)integerValue;
int intValue3 = integerValue;

reflection type checking?

I'd like to find a way to dynamically check if string is parse-able into a given type.
in other words,
public boolean canBeParsed(String type, String val) {
// use reflect to check if val can be parsed into type
}
clearly, I'd like to be able check different types with different values..
types will be strings like : Java.lang.Integer
---------- addition -------------
so for example, if I call this function,
canBeParsed("Java.lang.Integer", "1"); //returns true
canBeParsed("Java.lang.Integer", "HelloWorld"); //returns false
canBeParsed("Java.lang.String", "HelloWorld"); //returns true
canBeParsed("Java.lang.Boolean", "false"); // returns true
canBeParsed("Java.lang.Boolean", "HelloWorld"); //returns false
This method works with classes which declare a static valueOf method. Any class without this will return false. Several exceptions have been omitted to keep the code short.
Class<?> cls = Class.forName(type);
//Get a converter method, String to type
//Requires static method valueOf
Method converter;
try{
converter = cls.getDeclaredMethod("valueOf",new Class[]{String.class});
}catch(NoSuchMethodError ex){
//No conversion method found
return false;
}
if(!Modifier.isStatic(converter.getModifiers()){
//the method has to be static in order to be called by us
return false;
}
if(!cls.isAssignableFrom(converter.getReturnType())
//The conversion method has the wrong return type
return false;
try{
//try to parse the value
Object o = converter.invoke(null,new Object[]{value};
if( o == null)return false;//false if method returned null
else return true;//success
}catch(Exception ex)
{
//could not parse value
return false;
}
The valueOf(String) method is present in the wrapper classes Short,Long,Integer,Float,Double,Boolean so it supports these and any other class which has this method.
A dynamic type check is something different from what you are asking. With a dynamic check you check if an obect is an instance of a specific type (basically sametype or narrower type will be allowed) and you can do it with the instanceof operator. But this involves the object hierarchy and not the "can be converted to" concept that you would like to have. You can try with string instanceof Integer but this will be ALWAYS false.
In your situation you want to check if a string rapresents an integer number and you should do it in a different way:
try {
int number = Integer.parseInt(string);
}
catch (NumberFormatException e) {
System.out.println("String is not an integer string!");
}
Otherwise you could define a regex for every type and check what the string contains through it:
if (string.matches("[1-9][0-9]*"))
...
In anycase, since a String is just a string type and nothing else, the RTTI won't help you here. The string itself is orthogonal with every other type (int, float, whatever) also if it rapresents the textual version of another type.
A solution can be found if you can modify the source string types, in this case you could define for example an
class IntString extends String {
IntString(int i) {
super(Integer.toString(i));
}
}
then you could check if string instanceof IntString but this would work only if the strings are built with their specific type eg String s = new IntString(20).
Your easiest solution is probably a switch statement, with one case for each type that you want to support.
public boolean canBeParsed(String type, String val)
{
switch(type) {
case "Java.lang.Integer" : return(tryParseInteger(val) != null);
case ...
}
public static Integer tryParseInteger(String text) {
try {
return new Integer(text);
} catch (NumberFormatException e) {
return null;
}
}
In C# this would be easier, as there is an actual TryParse() method for each numeric type, and it's not necessary to catch an exception to test it.

Categories

Resources