What is Jython and why would we need it?
Java is a widely preferred language but it‘s not the best choice for every task. As programmers, we should always try to extend our knowledge, learn new languages and try to incorporate them in our day to day work. Python is one of the widely spread choices for building enterprise applications (maybe even more than Java) and we shouldn’t limit ourselves to only using one of them. There are multiple reasons we might need to integrate some python code in our existing Java application. It can be a library which is already there, an easier yaml processing or just because we like python. Whatever the reason, there is an easy way to achieve that by using Jython – the JVM implementation for the python language. It fully covers the python language and has the pip module manager.
Why Spring boot?
From my experience working in an bespoke development company, Spring is the de facto standard for enterprise applications in the recent years and by using interfaces and dependency injection we can seamlessly integrate our code with the existing java codebase. This way we can get the best out of both worlds and create even better products. In my example I will create a Spring Boot application with a service which is implemented in Jython. Spring Boot provides us with an easy way to get an up and running application in no time. The technique illustrated here is not limited to Spring Boot though. You can use it in a normal Spring application or another framework of choice.
Digging into the code
1.First, we need a simple Spring Boot application. I used the first one in the Spring tutorial – https://spring.io/guides/gs/spring-boot/
2.Then we need Jython (https://www.jython.org/ ). I installed version 2.7.1 to my PC and added the dependency to the pom.xml like that:
<dependency> <groupId>org.python</groupId> <artifactId>jython</artifactId> <version>2.7.1</version> </dependency>
An easier way would be to use jython-standalone artifact here which doesn’t require Jython installation and keeps most of the libraries in the JAR but it has limited functionality and doesn’t allow you to use external modules available through pip.
3.Now we create our interface
package hello; public interface HelloService { String getHello(); }
4.And a simple python implementation
from hello import HelloService class HelloServicePython(HelloService): def __init__(self): self.value="Hello from python" def getHello(self): return self.value
5.Injecting into the Spring context
Spring cannot create a bean from our python code easily, so we will provide a factory method that creates the object.
package hello; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PySystemState; import org.python.util.PythonInterpreter; import org.springframework.beans.factory.FactoryBean; public class HelloServiceFactory implements FactoryBean<HelloService> { @Override public HelloService getObject() throws Exception { //The python classpath is usually set by environment variable //or included in the java project classpath but it can also be set // programmatically. Here I hard code it just for the example. //This is not required if we use jython standalone JAR PySystemState systemState = Py.getSystemState(); systemState.path.append(new PyString("C:\jython2.7.1\Lib")); //Here is the actual code that interprets our python file. PythonInterpreter interpreter = new PythonInterpreter(); interpreter.execfile("python\HelloServicePython.py"); PyObject buildingObject = interpreter.get("HelloServicePython").__call__(); //Cast the created object to our Java interface return (HelloService) buildingObject.__tojava__(HelloService.class); } @Override public Class<?> getObjectType() { return HelloService.class; } }
6.And last step is to start using our Jython implementation in our spring boot application:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean(name = "helloServiceFactory") public HelloServiceFactory helloFactory() { return new HelloServiceFactory(); } @Bean(name = "helloServicePython") public HelloService helloServicePython() throws Exception { return helloFactory().getObject(); }
And our controller:
@RestController public class HelloController { @Autowired @Qualifier("helloServicePython") private HelloService service; @RequestMapping("/") public String index() { return service.getHello(); } }
7.Result
This is how our project looks in Eclipse and a screenshot of the result:
Conclusion
And that’s all. We can use our python implementation just as we would use a normal Spring service. That was just a simple example but it wouldn’t be much different if we need to create more complex python classes that rely on external libraries, etc. We can also extend Java classes in Python. It’s a powerful tool which can find many uses and advance our products to the next level!