Generic List and reflection - java

I'd like to call via reflection the following method, but I have problem to specify the correct signature:
public void executeRule(List<Node> params, SomethingStrangeFound callMeBack) throws IOException
{
...
}
I tried something like this:
Class partypes[] = new Class[2];
partypes[0] = Class.forName("java.util.List");
partypes[1] = Class.forName("vp.SomethingStrangeFound");
Method meth = cls.getMethod("executeRule", partypes);
It doesn't work because I use "java.util.List" when it must be "List<Node>", but I have no idea how to specify it.
If I just use "java.util.List", I have the following error calling cls.getMethod("executeRule", partypes):
NoSuchMethodException: vp.RuleWebXmlContextParamFacesPortletRenderStyles.executeRule(java.util.List, vp.SomethingStrangeFound)
Any help?
P.S.
At debug time, I see "List<Node>" is resolved with:
(Ljava/util/List<Lorg/w3c/dom/Node;>;Lit/vp/SomethingStrangeFound;)V
but it doesn't help me.

If both parameter classes are available at compile time you can initialize parameter array like this:
Class partypes[] = new Class[] { List.class, SomethingStrangeFound.class };
Method meth = cls.getMethod("executeRule", partypes);
This will guarantee that you have not mistyped qualified class names.
If this still does not work, check available methods in your class using Class#getMethods() method:
for (Method method : cls.getMethods()) {
System.out.println(method);
}

I ran your code and it worked for me.
You have not provided the definition of cls, but I assume it is something like
Class cls = RuleWebXmlContextParamFacesPortletRenderStyles.class;
Since you get a NoSuchMethodException, Class.forName already passed successfully, so no typo there (unless you have multiple SomethingStrangeFound classes, which would mean that you got the package wrong).
Because of this the last thing that comes to my mind is that perhaps you compiled RuleWebXmlContextParamFacesPortletRenderStyles before adding the method in question. Clean your code and recompile.

With partypes of size 2, getMethod will search for a method called "executeRule" with 2 parameters, one of type "java.util.list" and other of type "vp.SomethingStrangeFound"
But your method has only 1 parameter. You need to add a second parameter of type "vp.SomethingStrangeFound" to your method or set partypes size to 1.

Related

How to use methods of a wildcard class<?> result

I am trying to build a generic tool that finds a hibernate class and uses its methods by means of metadata.
So from the database I get 1: "TABLENAME" 2. "methodname"
Step 1. Finding the hibernate is done.
Class<?> result = generator.getClassFromTableName("TABLENAME");
Step 2. using the methods that are in the class that is returned is something I do not get.
Do i need to use classloader or finding it through result.getConstructors?
Easiest would be if I end up with an instance of 'TableName' and be able to acces all its methods. Hope it is clear!
Thanks #rsp for the reassurance to look within Reflection. First time to dive into it and in the end it was pretty straightforward.
Classloader to load class from string parameter
getConstructor to
find the right constructor and use it with newInstance()
getDeclaredMethod to find the right method and use it with Invoke and
the object instance
Class< ? > testdataClass = getClass().getClassLoader().loadClass(testDataClassname);
Constructor<?> tesdataClassConstructor = Objects.requireNonNull(testdataClass).getConstructor(datacontext);
Object testdataClassObject = tesdataClassConstructor.newInstance(dc);
Method buildMethod = testdataClass.getDeclaredMethod("build");
return buildMethod.invoke(testdataClassObject);

Java - How to pass the class of a generic type into a method

The method in JavaSparkContext.newAPIHadoopRDD takes class as a parameter.
In scala I was able to use the method like so:
sc.newAPIHadoopRDD(job.getConfiguration,
classOf[AvroKeyInputFormat[AvroFlumeEvent]],
classOf[AvroKey[AvroFlumeEvent]],
classOf[NullWritable])
How do i do that in java?
How do I pass the class of AvroKeyInputFormat<AvroFlumeEvent> into the method.
The closest I got was:
Class<AvroKeyInputFormat<AvroFlumeEvent>> inputFormatClass;
Class<AvroKey<AvroFlumeEvent>> keyClass;
JavaPairRDD<AvroKey<AvroFlumeEvent>, NullWritable> flumeEvents = sc.newAPIHadoopRDD(hadoopConf,
inputFormatClass,
keyClass,
NullWritable.class);
However, now it is complaining that inputFormatClass may not have been initialized. I think I'm missing something...
Variables in Java are either null, or an instance. Your variable inputFormatClass is neither null nor an instance, so you can't do anything to it until you initialize it. That's what it's complaining about.
As for passing the class in, you can do:
Class<AvroKeyInputFormat> clazz = AvroKeyInputFormat.class
Generic types are not stored at runtime - they are only used for verification. That's why you can't have a class of AvroKeyInputFormat<AvroFlumeEvent>

Understanding [[I.class referenced in some Java source

I'm looking at some Java reflection sourcecode that goes like this:
Method fixTransparentPixels = TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", new Class[] { [[I.class });
The method being referenced is declared like so:
private void fixTransparentPixels(int[][] p_147961_1_) {...}
What I do not understand is the [[I.class part. Now, I get that the actual Class[] array is to determine which form of the declared method you want (what parameter types etc.), but what does [[I.class actually mean?
Furthermore, when I try to write this reflection code myself, my IDE gives me syntax errors on the [[I.class bit. Can anyone give me any info on this?
Cheers.
When using getDeclaredMethod(String name, Class<?>... parameterTypes) the parameterTypes must be the class of the parameter (obviously). So in this case fixTransparentPixels require a int[][], so the parameterTypes will be int[][].class.
This will works :
TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", int[][].class);
[[I is the internal name of the class for int[][]:
System.out.println(int[][].class.getName()); outputs [[I
or Class.forName("[[I") == int[][].class.
However, it's illegal to write [[I.class in source code. You should write int[][].class instead.

EasyMock matcher for class data type

I am having nightmares with the syntax for this and easymock:
public void foo(Class<?> clazz);
EasyMock.expects(object.foo(EasyMock.isA(???)));
What should I be putting if my argument is String.class? I initially thought:
EasyMock.isA(((Class<?>)(String.class)).getClass())
Yet when I make the call foo(String.class) I get:
java.lang.IllegalStateException: missing behavior definition for the preceding method call:
You're attempting to verify a generic type that will be erased at runtime anyway.
Use a capture object instead:
Capture<Class<?>> classCapture = new Capture<Class<?>>();
EasyMock.expect(object.foo(EasyMock.capture(classCapture)));
// ... other test setup ...
Assert.assertEquals(classCapture.getValue(), String.class);
I think the following will also work as an expect statement if you don't want to use a Capture:
EasyMock.expects(object.foo(EasyMock.isA(String.class.getClass())));

DexClassLoader - invoke method with parameter

I have met some tutorials on the web, which are invoking simple methods and all I need is to invoke method "startDownload" which accepts Context as a parameter. I am now calling it:
Class<?> loaded = cl.loadClass("com.test.someclass");
Method m = loaded.getDeclaredMethod("startDownload", null);
m.invoke(this, null);
where c1 is DexClassLoader. But no success. I am getting error of NoSuchMethodException, I know I have to add parametres somewhere, but don't know where... any advices?
Thanks
I suggest looking at that post.
The parameters are passed after the method name when calling Class.getMethod(name, ...), as described here. You can directly use the class member of the Class you have to pass:
Method myMethod = myClass.getMethod("doSomethingWithAString", String.class);
Maybe you forgot some of them: the method won't be found if the signature (so the parameters) are not correct.

Categories