Override Java methods in Python using Pyjnius - java

I would like to use Pyjnius to create a Python class that extends a Java class and overrides some of its methods.
Specifically, these Java classes:
public class A {
public void test_method() {
System.out.println("In parent test_method!!!");
}
public static void run(A a) {
System.out.println("Running...");
a.test_method();
}
}
and
public class B extends A {
public void test_method() {
System.out.println("test method");
}
public static void main(String[] args) {
A.run(new B());
}
}
When I run that I see:
Running...
test method
How do I re-implement B in Python using Pyjnius?
This is my attempt:
import jnius_config
jnius_config.set_classpath('jars/testClasses.jar')
from jnius import autoclass, PythonJavaClass, JavaClass, MetaJavaClass, java_method
A = autoclass('test.pyjnius.A')
class B(A):
__javaclass__ = 'test/pyjnius/A'
#java_method('()Z')
def test_method(self):
print("test method")
A.run(B())
When I run the Python version I see this:
Running...
In parent test_method!!!
It isn't properly overriding test_method. How do I fix that?

The answer here is that what I am trying to do is not possible. The JVM cannot call the a method implemented in a Python subclass because it doesn't even know it exists.
The workaround is to implement the run method in class B, but make accommodations for the subclass's method. Something like this:
class B(A):
__javaclass__ = 'test/pyjnius/A'
#java_method('()Z')
def test_method(self):
print("test method")
def run(self):
A.runPart1(self)
self.test_method()
A.runPart2(self)
With runPart1 and runPart2 implemented in Java in a modified version of class A.

Related

classOf T instead of T$ for Java library that does reflection

I'm using Scala with a Java library that expects to be passed a class with a public static void main(java.lang.String[]) so it can run call it via reflection for integration tests.
object RestServer {
def main(args: Array[String]): Unit = { /* run the server */ }
}
Due to the behavior described in this answer to another question, this gets compiled to two classes.
public final class com.example.RestServer$ {
public static final com.example.RestServer$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
and
public final class com.example.RestServer {
public static void main(java.lang.String[]);
}
When I pass the class to the library
#IntegrationTest(main = classOf[RestServer.type])
class MyTests extends RapidoidIntegrationTest { }
I'm actually passing the object singleton instance (RestServer$), not the RestServer class that has the static void main() method.
This wouldn't be a problem, except the library verifies that the method it is calling is both public and static before calling it?
How can I get the RestServer class instead?
If you have control over the RestServer source file you can add an empty companion class.
object RestServer {
def main(args: Array[String]): Unit = { /* run the server */ }
}
class RestServer
That way Scala will recognize that a class RestServer exists, so classOf[RestServer] will compile and give you the class that contains the static method.

Kotlin top level function with private java contructor

I have the kotlin file with top level function and specified name for using it from java code:
Utility.kt
#file:JvmName("Utility")
package com.example
fun someUtilityFunc() {
// ignored
}
and I can instantiate Utility class in my Java code:
Main.java
package com.example;
public Main {
public static void main(String[] args) {
new Utility();
}
}
How can I add the private constructor to generated Utility class?
You can't. file:JvmName will generate a regular class with static methods.
If you absolutely don't want to have this constructor, you'll have to use object
object Utility {
fun someUtilityFunc() {
// ignored
}
}
Now previously, you could just called someUtilityFunc() in your Kotlin code, and it just worked.
But thankfully you can import functions in Kotlin, so it still works without prefixing:
import com.example.Utility.someUtilityFunc
fun main() {
someUtilityFunc()
}

How to check if class has methods added by aspect?

Suppose I have a simple class:
public class TestClass {
/*...*/
}
I created an aspect which injects new method to this class:
public aspect TestAspect {
public void TestClass.aspectMethod() {
/*...*/
}
}
Now, how can I check if TestClass has method added by TestAspect in runtime?
The simplest way would be to simply reflect on the class:
TestClass.class.getDeclaredMethod("aspectMethod")
which will throw NoSuchMethodException if it isn't there. Or if you have the bytes you could use a byte code visitor to check what methods exist in the byte code - but the reflective route would be less messing around.
Andy's answer is the correct one, I just want to answer your follow-up question from the comment:
Duck typing is not a Java feature, but if you use ITD in order to make the class implement an interface and then have an instance of your aspect-extended class you can use instanceof MyInterface in order to determine what you need to know. Other ways (also using reflection) are also available:
Interface with the method you want to add later via ITD:
package de.scrum_master.app;
public interface MyInterface {
void myMethod();
}
Sample driver application:
package de.scrum_master.app;
import java.lang.reflect.Type;
public class Application {
public static void main(String[] args) {
Application application = new Application();
// Use an instance
System.out.println(application instanceof MyInterface);
System.out.println(MyInterface.class.isInstance(application));
// Use the class
for (Type type : Application.class.getGenericInterfaces())
System.out.println(type);
for (Class<?> clazz : Application.class.getInterfaces())
System.out.println(clazz);
}
}
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
import de.scrum_master.app.MyInterface;
public aspect MyAspect {
declare parents : Application implements MyInterface;
public void Application.myMethod() {}
}
Application output:
true
true
interface de.scrum_master.app.MyInterface
interface de.scrum_master.app.MyInterface

Extending the main class in Java

I need to extend the functionality of my main class, by overriding some of its methods. I was expecting that the class extending the main class would be able to be run. However, Eclipse doesn't recognize MyLauncher as a runnable class. In the following code, I have a setup() method that is overridden by the subclass. What I want is a way to run the main(..) from the super class but also the setup from the subclass.
// Launcher.java
public class Launcher {
Launcher instance;
public static void main (args[]) {
instance = new Launcher(); // This is likely the problem
instance.setup();
}
public void setup() {
System.out.println("Default agent setup.");
}
}
// MyLauncher.java
public class MyLauncher extends Launcher {
public void setup() {
System.out.println("New agent setup!");
}
}
I accept alternatives to this. I can't add a main method to the subclass, though. The Launcher class is inside an API i'm making, so it can't refer to the class MyLauncher that is using the API.
edit: I think this is to specific to my problem. I decided to search for a new approach. Since I'm working with JDT, I'm going to parse the Launcher and inject the class.
Static methods are not inherited, they're always bound to the class that defines them, and need to be called explicitely.
In you case, the MyLauncher needs a main() method too, and could then delegate to the main() method of Launcher:
public class MyLauncher extends Launcher {
public static void main (String[] args) {
Launcher.main(args);
}
protected void setup() {
System.out.println("New agent setup!");
}
}
Protected methods can not be called from outside. So the MyLauncher.setup() do not override Launcher.setup() and instance.setup(); calls the public method from Class Launcher.
There can only be one main method in your project, that is one entry point to the program. So let's assume you're going to be keeping the main method in the Launcher class.
Your main method signature should be:
public static void main (String args[])
And unless you want the setup() method from the launcher to be called you'd want to do:
instance = new MyLauncher();
That would call the setup() method from MyLauncher.
If you want to call setup() from the Launcher class you need to instantiate the launcher class:
instance = new Launcher();
If you want to be able to run MyLauncher.setup(), the variable must be a MyLauncher. You are initializing and storing a Launcher in the main() function.
If the two classes are in the same package, or Launcher.java imports the MyLauncher class, then the main() function in Launcher should be able to be:
public class Launcher {
Launcher instance;
public static void main(String[] args) {
instance = new MyLauncher();
if(instance instanceof MyLauncher) {
((MyLauncher) instance).setup();
} else
{
instance.setup();
}
}
}
As you say, the fact that you create an instance of Launcher directly in main means that no inheritance is available. Even if you could start MyLauncher easily from Eclipse, within the main method you wouldn't know which type had actually been used to start it. I can't see any easy solution that doesn't involve either creating a main method in each class or providing the class name as a command-line argument. I would probably separate the "running" from anything else:
public class Launcher {
public static void launch(LaunchConfiguration configuration) {
configuration.setup();
...
}
}
public class LaunchConfiguration {
public static void main(String[] args) {
Launcher.launch(new LaunchConfiguration());
}
public void setup() {
}
}
public class MyLaunchConfiguration {
public static void main(String[] args) {
Launcher.launch(new MyLaunchConfiguration());
}
#Override
public void setup() {
}
}

Strange behaviour on method annotations and default access level

Here's my problem...
I have an annotation in package pkg3:
package pkg3;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TestAnno {
}
Also I have two classes in package pkg1, one with public access and one with default access
package pkg1;
import pkg3.TestAnno;
class Class1 {
#TestAnno
public void test1() { }
public void test2() { }
}
and
package pkg1;
import pkg3.TestAnno;
public class Class2 extends Class1 {
#TestAnno
public void test3() { }
public void test4() { }
}
Finnally I've got a main class in package pkg2
package pkg2;
import java.lang.reflect.Method;
import pkg1.Class2;
import pkg3.TestAnno;
public class MainClass {
public static void main(String[] args) {
Class2 cls = new Class2();
for(Method m: cls.getClass().getMethods()) {
System.out.println(m);
if (m.getAnnotation(TestAnno.class) != null) {
System.out.println(" > hass anno");
}
}
}
}
Running this example I expect to see the info, that two methods have #TestAnno present - test1 and test3, but I only see one test3, and... what is strange, the methods test1 and test2 are listed as they were be declared in class Class2.
public void pkg1.Class2.test3()
> hass anno
public void pkg1.Class2.test4()
public void pkg1.Class2.test1()
public void pkg1.Class2.test2()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
... rest methods from java.lang.Object
I know, that getMethods returns only public methods from given glass (and it's all super classes) but... this is strange for me.
I'm using this in order to separate generated classes (which have default access) from implementation classes (which are public and they're extending generated classes).
Have I to use public access in generated classes (I wanted them not to be visible to rest of the world) or is there any way to get annotated public methods from Class1 ?
This answer is just a "one big maybe" made by a man at 3 a.m. so it will require JLS confrontation, better terminology and more informations. I was planning to post it as comment but unfortunately it is too long :/
Lets take a look at this classes
class SomeClass {
#TestAnno
public void test(){}
}
class SomeDefaultClass extends SomeClass {
}
public class SomePublicClass extends SomeClass {
}
now take a look at this code and its result
Method m1 = SomePublicClass.class.getMethod("test");
Method m2 = SomeDefaultClass.class.getMethod("test");
System.out.println(m1 + "\t> " + m1.getAnnotation(TestAnno.class));
System.out.println(m2 + "\t\t> " + m2.getAnnotation(TestAnno.class));
output
public void SomePublicClass.test() > null
public void SomeClass.test() > #TestAnno()
As you see public class that extends class with package modifier doesn't inherit annotations, but class with package modifier does.
Why is that?
Both SomeDefaultClass and SomePublicClass "inherited" test() method but not in the same way.
If you take a look at result of javap SomeDefaultClass.class you will see
class SomeDefaultClass extends SomeClass {
SomeDefaultClass();
}
so it doesn't have test() method in its binaries, so it will use it from SomeClass which have TestAnno annotation.
On the other hand if you take a look at result of javap SomePublicClass you will see
public class SomePublicClass extends SomeClass {
public SomePublicClass();
public void test();
}
which means that code of test() method has been overridden in SomePublicClass so this method has been declared again in SomePublicClass but unfortunately without previous annotations and since overridden method doesn't have annotations you wont see them in your code. (Why annotations are not added when compiler is overriding method? Honestly, I don't know :/)
Why is overriding happening? I suspect that since SomePublicClass is public and test is also public it should be accessible from all packages, but since SomeClass has default/package visibility this method couldn't be accessible via SomeClass from outside of its package.
To prevent moving/copying test method from one class to another you can make both classes public or default/package.

Categories