This content originally appeared on DEV Community and was authored by w4t3r
Introduction
If you have an idea or experience with Java + Python integration, I am going to show you how to make a simple connection between these programming languages in the Spring Boot ecosystem.
Also, for additional information about spring-boot-python-executor
you can check out the repository of the project: https://github.com/w4t3rcs/spring-boot-python-executor
Project Setup
Add the starter dependency in pom.xml
:
<dependency>
<groupId>io.github.w4t3rcs</groupId>
<artifactId>spring-boot-python-executor-starter</artifactId>
<version>1.0.0</version>
</dependency>
Or to your build.gradle
:
implementation 'io.github.w4t3rcs:spring-boot-python-executor-starter:1.0.0'
Also, I’d like to suggest using Docker as a sandbox for Python script execution, so add to your docker-compose.yaml
this:
services:
python-grpc-server:
image: "w4t3rcs/spring-boot-python-executor-python-grpc-server:latest"
ports:
- "50051:50051"
environment:
PYTHON_SERVER_TOKEN: secret
PYTHON_ADDITIONAL_IMPORTS: scikit-learn,numpy,pandas,scipy
And your basic application.yaml
should look like this:
spring:
python:
executor:
type: grpc
grpc:
token: secret
Developing the first Services with Python
In this chapter, I’ll show you how to communicate with Python code by coding out first simple classes that use Python.
Our first example is going to be just a simple class that executes Python code without any difficult logic:
SimplePythonService
@Slf4j
@Service
@RequiredArgsConstructor
public class SimplePythonService {
private static final String SIMPLE_SCRIPT = "simple_script.py";
private static final String NUMERIC_SCRIPT = "numeric_script.py";
private static final String DICT_SCRIPT = "dict_script.py";
private final PythonProcessor pythonProcessor;
@PythonBefores({
@PythonBefore(SIMPLE_SCRIPT),
@PythonBefore(NUMERIC_SCRIPT),
@PythonBefore(DICT_SCRIPT),
})
public void doSomethingWithPythonBefore() {
log.info("doSomethingWithPythonBefore()");
}
public void doSomethingWithPythonInside() {
log.info("doSomethingWithPythonInside()");
log.info("1 --> {}", pythonProcessor.process(SIMPLE_SCRIPT, String.class));
log.info("2 --> {}", pythonProcessor.process(NUMERIC_SCRIPT, Float.class));
log.info("3 --> {}", pythonProcessor.process(DICT_SCRIPT, DictScriptResponse.class));
}
@PythonAfters({
@PythonAfter(SIMPLE_SCRIPT),
@PythonAfter(NUMERIC_SCRIPT),
@PythonAfter(DICT_SCRIPT),
})
public void doSomethingWithPythonAfter() {
log.info("doSomethingWithPythonAfter()");
}
}
simple_script.py
hello_world = 'Hello World'
print(hello_world)
o4java{hello_world}
numeric_script.py
a = 2.3462
b = 14.151
c = a + b
o4java{c}
dict_script.py
result = {
"x": "Hello World",
"y": 12345
}
o4java{result}
In this example, we can see different types of executing Python scripts using PythonBefore
or PythonAfter
annotations, or PythonProcessor
object.
- Use
PythonBefore
if you want to execute a Python script before a Java method and forget about it. -
PythonProcessor
is used for advanced purposes: getting the result of the Python script execution as a Java object and argument configuration. It is a centralized object for executing Python scripts in the library. - Use
PythonAfter
if you want to execute a Python script after a Java method. -
o4java{…}
means that this Python field will be returned as a Java object.
More advanced example with Spelython usage
PriceCalculatorPythonService
@Service
@RequiredArgsConstructor
public class PriceCalculatorPythonService {
private static final String CALCULATOR_SCRIPT = "price_calculator.py";
private final PythonProcessor pythonProcessor;
public double calculatePrice(ProductDto product, CustomerDto customer) {
int randomMultiplier = new Random().nextInt(10);
product.setBasePrice(product.getBasePrice() * randomMultiplier);
Map<String, Object> arguments = Map.of(
"product", product,
"customer", customer
);
PythonExecutionResponse<Double> response = pythonProcessor.process(CALCULATOR_SCRIPT, Double.class, arguments);
return response.body();
}
}
price_calculator.py
base_price = spel{#product.getBasePrice()}
discount = 0
# Apply customer loyalty discount
if spel{#customer.loyaltyYears()} > 2:
discount += 0.05
# Apply volume discount
if spel{#product.getQuantity()} > 10:
discount += 0.03
final_price = base_price * (1 - discount)
# Return the calculated price to Java
o4java{final_price}
This example shows how to use Spelython (SpEL + Python) in your Python script. Write SpEL expressions inside spel{…}
, and the special SpelythonResolver
object will resolve it as a JSON object in your Python script.
Advanced machine learning example
MLPythonService
@Slf4j
@Service
@RequiredArgsConstructor
public class MLPythonService {
private static final String ML_SCRIPT = "ml_script.py";
private final PythonProcessor pythonProcessor;
public double processMLScript(String text) {
Map<String, Object> arguments = Map.of("text", text);
PythonExecutionResponse<Double> response = pythonProcessor.process(ML_SCRIPT, Double.class, arguments);
return response.body();
}
}
ml_script.py
# Required imports
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
# Simple sentiment analysis using predefined positive and negative words
positive_words = ['good', 'great', 'excellent', 'amazing', 'wonderful', 'best', 'love']
negative_words = ['bad', 'terrible', 'awful', 'worst', 'hate', 'poor', 'disappointing']
# Get the input text from Java
text = spel{#text}.lower()
# Count positive and negative words
positive_count = sum(1 for word in positive_words if word in text)
negative_count = sum(1 for word in negative_words if word in text)
# Calculate sentiment score (-1 to 1)
total = positive_count + negative_count
if total == 0:
sentiment = 0
else:
sentiment = (positive_count - negative_count) / total
# Return the sentiment score to Java
o4java{sentiment}
Conclusion
spring-boot-python-executor
enables safe and modular Python integration into Spring Boot applications. With AOP, REST, and gRPC support, the library is production-ready and easily extensible for custom use cases.
This content originally appeared on DEV Community and was authored by w4t3r