Having problems with a factory class, I pass in a human readable name that maps to a class that has a single constructor with a single argument, I get the following error:
java.lang.NoSuchMethodException: com.satgraf.evolution2.observers.VSIDSTemporalLocalityEvolutionObserver.<init>(com.satlib.evolution.ConcreteEvolutionGraph)
at java.lang.Class.getConstructor0(Class.java:2892)
at java.lang.Class.getConstructor(Class.java:1723)
at com.satlib.evolution.observers.EvolutionObserverFactory.getByName(EvolutionObserverFactory.java:84)
at com.satgraf.evolution2.UI.Evolution2GraphFrame.main(Evolution2GraphFrame.java:229)
These are the classes in question, I have about a dozen of these things in different projects, they all work without problem - including one that is almost identical, can't see why this one is failing:
public EvolutionObserver getByName(String name, EvolutionGraph graph){
if(classes.get(name) == null){
return null;
}
else{
try {
Constructor<? extends EvolutionObserver> con = classes.get(name).getConstructor(graph.getClass());
EvolutionObserver i = con.newInstance(graph);
observers.add(i);
return i;
}
catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException | IllegalArgumentException | SecurityException ex) {
Logger.getLogger(EvolutionObserverFactory.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
}
The class being instantiated is:
public class VSIDSTemporalLocalityEvolutionObserver extends JPanel implements EvolutionObserver{
public VSIDSTemporalLocalityEvolutionObserver(EvolutionGraph graph){
...
}
...
}
The argument graph is of type:
public class ConcreteEvolutionGraph extends ConcreteCommunityGraph implements EvolutionGraph{
...
}
getConstructor requires an exact match on the parameter types; it does not attempt to find a 'compatible' constructor. The getConstructor Javadoc simply says "The constructor to reflect is the public constructor of the class represented by this Class object whose formal parameter types match those specified by parameterTypes." (In current OpenJDK, getConstructor delegates to getConstructor0 which loops through all the constructors and compares the given parameter array against constructor.getParameterTypes().)
At runtime, your code looks for a constructor taking a parameter of type ConcreteEvolutionGraph (graph.getClass() returns graph's runtime type), and VSIDSTemporalLocalityEvolutionObserver doesn't have one.
If you're really looking for a constructor taking EvolutionGraph, pass EvolutionGraph.class to getConstructor instead. If instead you want any constructor that could be called with the graph's runtime type, you'll need to manually loop over the result of getConstructors() looking for a single-argument constructor for which graph.getClass().isAssignableTo(ctor.getParameterTypes()[0]). Note there may be more than one, and when interfaces are involved, there may not be a most-specific one. You'll have to decide how to break ties.
Related
I'm studying this piece of code and got stucked in the commented row:
protected <T> T creaOggetto(Class<T> classe, int id) {
try {
Package pacchetto = classe.getPackage();
String nomePacchetto = pacchetto.getName();
String nomeClasse = classe.getSimpleName();
String nomeClasseRisultato = nomePacchetto + ".impl." + nomeClasse + "Impl";
Class<?> classeRisultato = Class.forName(nomeClasseRisultato);
Constructor<?> costruttore = classeRisultato.getConstructor(new Class[] {int.class});
#SuppressWarnings("unchecked")
T risultato = (T)costruttore.newInstance(new Object[] {id});
return risultato;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
I know that getConstructor() returns the constructor object for that class but (new Class[] {int.class}) confuses me, what is his purpose?
According Java docs:
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
Returns a Constructor object that reflects the specified public
constructor of the class represented by this Class object. The
parameterTypes parameter is an array of Class objects that identify
the constructor's formal parameter types, in declared order. If this
Class object represents an inner class declared in a non-static
context, the formal parameter types include the explicit enclosing
instance as the first parameter.
So, classeRisultato.getConstructor(new Class[] {int.class}); returns the constructor that accepts one and only one int parameter or NoSuchMethodException if it doesn't exist.
In code you posted, note that, using that constructor, it creates a new instance of that class passing the id, that is the actual int argument:
T risultato = (T)costruttore.newInstance(new Object[] {id});
The getConstructor(new Class[]); method takes in an array of Classes that represent the parameters of the constructor you want to get.
For example, if you had a constructor in class X,
public X(int a, int b)
you could obtain said constructor using X.getClass().getConstructor(new Class[] {int.class, int.class});
The two int.class parameters in the array represent the two ints the the constructor take in.
Java Documentation
Since there are potentially multiple constructors, you need to specify the signature of the constructor to get the one you want when you call Class.getConstuctor.
The signature includes the type parameters to the constructor. The signature also includes the method name, but for a constructor the method name is always the class name in the source code, and it is always "<init>" in the compiled code, so you need not specify that.
So if you have new Class[] {int.class} then you are saying the signature consists of a single parameter of type "int". Which means you want the constructor X(int x) for class name X (note it is only the type of the parameters that matters, not the names of the parameter variables).
Also note that int.class resolves to java.lang.Integer.TYPE, which is used to denote the primitive type "int".
Is it possible to invoke a method where the argument object or the argument class is a subclass and the method himself took the superclass as argument?
I trying to invoke this method public void setNewProblem(Problem problem); with a concrete implementation of the abstract class Problem. Unfortunately I get an NoSuchMethodException exception.
I call the invoke like this:
Method method = model.getClass().getMethod("set" + propertyName, new Class[] { newValue.getClass() });
method.invoke(model, newValue);
If I change newValue.getClass() to Problem.class everything works fine. Any idea how to pass a subclass to public void setNewProblem(Problem problem);?
You have to ask for the exact type it is. This is because you can have multiple possible overloaded methods and it needs to know exact what you wanted.
So you can invoke with a sub-class but you cannot ask for a sub-class without be being there.
What you can do is look at all methods and find a match.
If all you need is the setter or getter for a property, I suggest you look at BeanIntrospector which will find you all the properties and the getter/setter methods for that property.
The problem is that newValue.getClass() is a subclass of the class in the declared method.
From Class.getMethod:
To find a matching method in a class C: If C declares exactly one
public method with the specified name and exactly the same formal
parameter types, that is the method reflected.
You could work your way up the inheritance chain until it works:
Method getMethod(Class c1, Class c2) {
if(c2.getSuperClass() == null) {
return c1.getMethod("set" + propertyName, new Class[] { c2 });
}
try {
return c1.getMethod("set" + propertyName, new Class[] { c2 });
} catch(NoSuchMethodException e) {
return getMethod(c1, c2.getSuperClass());
}
}
Usage:
Method method = getMethod(model.getClass(), newValue.getClass());
I hesitate to suggest this, however, since it does not cover 100% of cases (such as if the formal argument class is an interface), and the way you are doing this is bad.
When you call Class.getMethod() you have to specify correctly the formal argument types. Not the types of the actual arguments you are planning to supply. You have to match precisely what it says in the declaration of the method concerned.
"The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order."
See Boolean#TYPE for an example of what I'm referring to.
All of the wrapper classes (Boolean, Double, Integer, etc) have a static Class field associated with them called TYPE. What is the meaning of this?
Specifically, here are a few soft tests:
System.out.println(Boolean.class == Boolean.TYPE);
System.out.println(Boolean.TYPE.isInstance(Boolean.valueOf(true)));
Both evaluate as false. (And as a side note, an .equals comparison is unnecessary since Class does not override equals from Object.)
Both Boolean.class and Boolean.TYPE are Class<Boolean> because they are == comparable without an error. Comparing two objects with differently declared generic types is illegal.
On further inspection, the TYPE fields are retrieved by calling a package-private native method Class#getPrimitiveClass along the lines of the following:
public static final Class<Boolean> TYPE = Class.getPrimitiveClass("boolean");
The comment on the method itself is not particularly informative either. It says it returns the VM's class object for the type which is fairly obvious since it is a native method.
I can't find any documentation on this beyond the Java docs' vague allusion to "representing the primitive type". Is there some kind of use for this field? It's unused in the wrapper classes themselves.
(Edited)
System.out.println(boolean.class == Boolean.TYPE);
Is true.
Also one use is then reflection:
try {
Constructor ctor = Boolean.class.getConstructor(Boolean.class);
} catch (Exception e) {
System.out.println("NoSuchMethodException gets thrown");
}
try {
Constructor ctor = Boolean.class.getConstructor(Boolean.TYPE);
System.out.println(ctor.newInstance(true));
} catch (Exception e) {
// (no exception thrown)
}
And I've found some SO threads that cite that, such as this one. I guess I came from the "wrong end" of Google so-to-speak to not find any results on it.
But considering the existence of the "primitive classes" (boolean.class, int.class etc.) that doesn't really explain the TYPE field existence. Basically it's "just there"? I still don't really get it.
The class representing the primitive type is useful in specifying or examining methods that take or return primitives. For example, if your class has a method that looks like this
class Test {
static int round(float val) {...}
}
and you wish to access this method through reflection, you would need to do this:
Method round = Test.class.getMethod("round", Float.TYPE);
You can examine the return type, too:
if (round.getReturnType == Integer.TYPE) {
System.out.println("Method 'round' returns an int.");
}
Using Float.class instead
Method round = Test.class.getMethod("round", Float.class);
would not work, because that would pull a different method - this one:
static int round(Float val) {...}
(Don't have the rep to comment, so must answer.)
To put it succinctly: Float.TYPE == float.class, and Float.class != float.class. Consider:
class Test {
void func() {
Class clazz;
// The two statements do the same thing. On my system, they even compile
// to the same bytecode.
clazz = Integer.TYPE; // explicitly asking for this
clazz = int.class; // must yield the same object as above.
// Both of these below are valid, as the `true' is autoboxed. In
// Java < 1.5, both had to be explicitly boxed
Test.class.getMethod("test", Boolean.class).invoke(this, true);
// calls method A
Test.class.getMethod("test", boolean.class).invoke(this, true);
// calls method B. Could also use getMethod("test", Boolean.TYPE)
}
void test(Boolean b) { System.out.println("Method A"); }
void test(boolean b) { System.out.println("Method B"); }
}
I would assume both int.class andInteger.TYPE have been around from the beginning of Java, though I may be wrong. Integer.TYPE can be initially assigned with Class.getPrimitiveClass("int").
I'm trying to build a generic class loader. I need to check classes that I load against a method argument to determine if they are of the same class.
The code mostly explains what I'm trying to do.
private static LinkedList<Object> loadObjectsInDirectory(Class class0, File dir) throws ClassNotFoundException {
LinkedList<Feature> objects = new LinkedList<Object>();
ClassLoader cl = new GenericClassLoader();
for(String s : dir.list()) {
Class class1 = cl.loadClass(s);
try {
Object x = class1.newInstance();
if (x instanceof (!!! class0 !!!) ) {
objects.add(x);
}
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
}
return objects;
}
How is this achieved?
Looks like you need the isAssignableFrom method
if (kelass.isAssignableFrom(klass)) {
objects.add(x);
}
JavaDoc
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion. See The Java Language Specification, sections 5.1.1 and 5.1.4 , for details.
I use a class that makes my Hibernate Query through a FilterCriterionList (sort of finder) and it's always worked perfectly until now and triggers a NullPointerException and I have absolutely no idea as to why it's triggered.
This is the method (in ReflectionUtil) that triggers the nullpointer with the following values (mind you that the other values thrown at it work perfectly and it's just these that seem to give an error):
type = interface java.util.List
fieldName = parameter
First it throws the NoSuchFieldException and on it's second run (as it's called again at field = getField(type.getSuperclass(), fieldName);) makes it throw a NullPointerException and just stop dead (all of this happens in my UnitTest, not a live environment yet).
public static Field getField(Class type, String fieldName) {
Field field = null;
try {
field = type.getDeclaredField(fieldName);
} catch (Exception e) {
if (!type.equals(Object.class)) {
field = getField(type.getSuperclass(), fieldName);
}
}
return field;
}
Any ideas as to why this happens (or what I can do to fix it?). I can't really show off more code as it's quite complicated and it's company code.
java.util.List is an interface, therefore calling getSuperclass() on it results in null.
The correct way to apply getField() recursively is the following:
} catch (Exception e) {
Class superclass = type.getSuperclass();
if (superclass != null) {
field = getField(superclass, fieldName);
}
}
You called like this:
getField(List.class, "parameter");
It would have never worked as List is an interface and it doesen't have any field called parameter. For the second call, its' null because interface List doesnet have a superclass.
From the Class.getSuperclass documentation
Returns the Class representing the
superclass of the entity (class,
interface, primitive type or void)
represented by this Class. If this
Class represents either the Object
class, an interface, a primitive type,
or void, then null is returned. If
this object represents an array class
then the Class object representing the
Object class is returned.