You could also use Py4J. There is an example on the frontpage and lots of documentation, but essentially, you just call Java methods from your python code as if they were python methods:
from py4j.java_gateway import JavaGateway
gateway = JavaGateway() # connect to the JVM
java_object = gateway.jvm.mypackage.MyClass() # invoke constructor
other_object = java_object.doThat()
other_object.doThis(1,'abc')
gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method
As opposed to Jython, one part of Py4J runs in the Python VM so it is always "up to date" with the latest version of Python and you can use libraries that do not run well on Jython (e.g., lxml). The other part runs in the Java VM you want to call.
The communication is done through sockets instead of JNI and Py4J has its own protocol (to optimize certain cases, to manage memory, etc.)
Disclaimer: I am the author of Py4J
Answer from Barthelemy on Stack OverflowCalling Java from Python - Stack Overflow
Convert Java class structures to Python classes - Stack Overflow
Does python have an equivalent to Java Class.forName()? - Stack Overflow
using python class methods inside java - Stack Overflow
Videos
You could also use Py4J. There is an example on the frontpage and lots of documentation, but essentially, you just call Java methods from your python code as if they were python methods:
from py4j.java_gateway import JavaGateway
gateway = JavaGateway() # connect to the JVM
java_object = gateway.jvm.mypackage.MyClass() # invoke constructor
other_object = java_object.doThat()
other_object.doThis(1,'abc')
gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method
As opposed to Jython, one part of Py4J runs in the Python VM so it is always "up to date" with the latest version of Python and you can use libraries that do not run well on Jython (e.g., lxml). The other part runs in the Java VM you want to call.
The communication is done through sockets instead of JNI and Py4J has its own protocol (to optimize certain cases, to manage memory, etc.)
Disclaimer: I am the author of Py4J
Here is my summary of this problem: 5 Ways of Calling Java from Python
http://baojie.org/blog/2014/06/16/call-java-from-python/ (cached)
Short answer: Jpype works pretty well and is proven in many projects (such as python-boilerpipe), but Pyjnius is faster and simpler than JPype
I have tried Pyjnius/Jnius, JCC, javabridge, Jpype and Py4j.
Py4j is a bit hard to use, as you need to start a gateway, adding another layer of fragility.
So is there any way to generate simple "Pojo" Python classes from Java code?
I had a go at it and below is the solution:
Considering below simplistic Pojo.java
public class Pojo {
private String string = "default";
public int integer = 1;
public String getString(){
return string;
}
}
The solution will need 3 phases
1. Java Pojo to JSON Schema
I could find below options:
- FasterXML/jackson-module-jsonSchema: This is the base, which below libraries also use internally.
- mbknor/mbknor-jackson-jsonSchema: Officially cited by above to support the v4 of the json schema.
- reinert/JJSchema
With below relevant code with option 1(also go through the site):
ObjectMapper MAPPER = new ObjectMapper();
JsonSchemaGenerator generator = new JsonSchemaGenerator(MAPPER);
JsonSchema jsonSchema = generator.generateSchema(Pojo.class);
System.out.println(MAPPER.writeValueAsString(jsonSchema));
Below output json schema string is got:
{"type":"object","id":"urn:jsonschema:Pojo","properties":{"string":{"type":"string"},"integer":{"type":"integer"}}}
2. JSON Schema post-process
This phase is required mainly because I found that for the simplistic use case(at least), Step 3 below needs a json schema that has a definitions property mandatorily. I guess this is because of the evolving schema definitions @ http://json-schema.org/. Also, we can include a title property to specify the name of the python class that next step will generate.
We can easily accomplish these in the java program of Step 1 above as a post step. We need a json schema string of below form:
{"definitions": {}, "title": "Pojo", "type":"object","id":"urn:jsonschema:Pojo","properties":{"string":{"type":"string"},"integer":{"type":"integer"}}}
Notice that only addition is "definitions": {}, "title": "Pojo"
3. Json schema to Python class
frx08/jsonschema2popo seems to be doing this job quite nicely.
pip install jsonschema2popo
jsonschema2popo -o /path/to/output_file.py /path/to/json_schema.json
Some more points
- The Java-Json schema generators will only include those properties in the output which are either public or have a public getter.
- I assume that for a mass migration annotating the Java classes will be a pain. Otherwise, if this is feasible to you, all the above java libraries provide rich annotations where you can specify whether a property is mandatory and much more.
TechWalla @https://www.techwalla.com/articles/how-to-convert-java-to-python has detailed instructions. See if it helps you.
Pasting the instructions here Step 1 Download and extract java2python. The file you download is a gzip file, and it contains within it a tarball file; both are compression schemes, and both can be decompressed with 7zip, an open-source program.
Step 2 Place the contents of the java2python folder on the root of your C:\ drive.
Step 3 Open a command prompt and navigate to "C:\java2python\" before typing in "python setup.py install" without quotes. This will tell the Python interpreter to run the setup script and prepare your computer. Change directories to "C:\java2python\bin\" and keep the window open.
Step 4 Copy the Java file to be converted into your bin subfolder, under java2python. In the command line, run "j2py -i input_file.java -o output_file.py," replacing the input_file and output_file with your filenames.
Step 5 Open the new Python folder and read the code. It probably won't be perfect, so you'll need to go over it to make sure it makes sense from a Python point of view. Even spending time manually checking, however, you will have saved large amounts of time from hand-converting
Reflection in python is a lot easier and far more flexible than it is in Java.
I recommend reading this tutorial (on archive.org)
There's no direct function (that I know of) which takes a fully qualified class name and returns the class, however you have all the pieces needed to build that, and you can connect them together.
One bit of advice though: don't try to program in Java style when you're in python.
If you can explain what is it that you're trying to do, maybe we can help you find a more pythonic way of doing it.
Here's a function that does what you want:
def get_class( kls ):
parts = kls.split('.')
module = ".".join(parts[:-1])
m = __import__( module )
for comp in parts[1:]:
m = getattr(m, comp)
return m
You can use the return value of this function as if it were the class itself.
Here's a usage example:
>>> D = get_class("datetime.datetime")
>>> D
<type 'datetime.datetime'>
>>> D.now()
datetime.datetime(2009, 1, 17, 2, 15, 58, 883000)
>>> a = D( 2010, 4, 22 )
>>> a
datetime.datetime(2010, 4, 22, 0, 0)
>>>
How does that work?
We're using __import__ to import the module that holds the class, which required that we first extract the module name from the fully qualified name. Then we import the module:
m = __import__( module )
In this case, m will only refer to the top level module,
For example, if your class lives in foo.baz module, then m will be the module foo
We can easily obtain a reference to foo.baz using getattr( m, 'baz' )
To get from the top level module to the class, have to recursively use gettatr on the parts of the class name
Say for example, if you class name is foo.baz.bar.Model then we do this:
m = __import__( "foo.baz.bar" ) #m is package foo
m = getattr( m, "baz" ) #m is package baz
m = getattr( m, "bar" ) #m is module bar
m = getattr( m, "Model" ) #m is class Model
This is what's happening in this loop:
for comp in parts[1:]:
m = getattr(m, comp)
At the end of the loop, m will be a reference to the class. This means that m is actually the class itslef, you can do for instance:
a = m() #instantiate a new instance of the class
b = m( arg1, arg2 ) # pass arguments to the constructor
Assuming the class is in your scope:
globals()'classname'
Otherwise:
getattr(someModule, 'classname')(args, to, constructor)
Edit: Note, you can't give a name like 'foo.bar' to getattr. You'll need to split it by . and call getattr() on each piece left-to-right. This will handle that:
module, rest = 'foo.bar.baz'.split('.', 1)
fooBar = reduce(lambda a, b: getattr(a, b), rest.split('.'), globals()[module])
someVar = fooBar(args, to, constructor)