Type Conversion API¶
The type_conversion module provides utilities for converting between Python and Java types when working with ArcadeDB's Java backend.
Overview¶
The type_conversion module enables:
- Automatic Conversion: Seamless Python ↔ Java type conversion
- Collection Handling: Lists, sets, maps, and nested structures
- Date/Time Support: datetime, date, and time objects
- Decimal Precision: High-precision decimal numbers
- Binary Data: Bytes and byte arrays
- Type Safety: Validation and error handling
Why Type Conversion?¶
ArcadeDB Python bindings wrap a Java database engine. When you:
- Set properties on records → Python values converted to Java
- Read properties from records → Java values converted to Python
- Pass query parameters → Python values converted to Java
- Receive query results → Java values converted to Python
The type_conversion module handles this automatically.
Conversion Functions¶
convert_python_to_java¶
from arcadedb_embedded.type_conversion import convert_python_to_java
java_value = convert_python_to_java(python_value)
Convert Python value to Java object for ArcadeDB.
This function only converts the types listed below explicitly. All other Python
values (bool, int, float, str, bytes, and any Java objects) are returned
as-is so that JPype performs the conversion automatically.
Supported Conversions:
| Python Type | Java Type |
|---|---|
None |
null |
Decimal |
BigDecimal |
set |
HashSet |
dict |
HashMap |
list |
ArrayList |
tuple |
ArrayList |
datetime |
java.util.Date |
date |
LocalDate |
Notes:
datetimeis converted to ajava.util.Datebuilt from its epoch milliseconds.dateis converted to aLocalDate. If the Java types are unavailable it is combined withtime.minand converted as adatetime.- Collection elements, set members, and map keys/values are converted recursively.
Example:
from arcadedb_embedded.type_conversion import convert_python_to_java
from datetime import datetime
from decimal import Decimal
# Primitive types
java_int = convert_python_to_java(42)
java_str = convert_python_to_java("hello")
java_bool = convert_python_to_java(True)
# Date/time
java_datetime = convert_python_to_java(datetime.now())
# Decimal
java_decimal = convert_python_to_java(Decimal("123.456"))
# Collections
java_list = convert_python_to_java([1, 2, 3])
java_dict = convert_python_to_java({"key": "value"})
# Nested structures
java_nested = convert_python_to_java({
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
})
convert_java_to_python¶
from arcadedb_embedded.type_conversion import convert_java_to_python
python_value = convert_java_to_python(java_value)
Convert Java object to Python value.
Supported Conversions:
| Java Type | Python Type |
|---|---|
null |
None |
Boolean |
bool |
String, Character |
str |
Integer, Long, Short, Byte |
int |
Float, Double |
float |
BigDecimal |
Decimal |
BigInteger |
int |
java.util.Date |
datetime |
LocalDate |
date |
LocalDateTime |
datetime |
Instant, ZonedDateTime |
datetime (UTC) |
Map |
dict |
Set |
set |
List, Collection |
list |
Notes:
InstantandZonedDateTimeare returned as timezone-awaredatetimeobjects in UTC.- Other indexable Java objects (such as primitive arrays) are converted element-by-element to a
list. - Unrecognized Java objects (for example
Vertex,Edge,Document) are returned unchanged.
Example:
from arcadedb_embedded.type_conversion import convert_java_to_python
# Read from database (automatic conversion)
result = list(db.query("sql", "SELECT FROM User WHERE username = 'alice'"))[0]
# Get Python properties (automatically converted)
username = result.get("username") # str
age = result.get("age") # int
tags = result.get("tags") # list
profile = result.get("profile") # dict
# Manual conversion (if needed for custom types)
element = result.get_element()
java_property = element.get("username") # Uses wrapper method
# Properties are automatically converted
Type-Specific Conversions¶
Integers¶
from arcadedb_embedded.type_conversion import convert_python_to_java
# Small integers → Integer
java_int = convert_python_to_java(42) # Java Integer
# Large integers → Long
java_long = convert_python_to_java(2**40) # Java Long
# Reading integers with SQL parameter binding
with db.transaction():
db.command("sql", "INSERT INTO User SET age = ?", 30) # Python int → Java Integer
age = db.query("sql", "SELECT age FROM User LIMIT 1").first().get("age")
Floats and Decimals¶
from arcadedb_embedded.type_conversion import convert_python_to_java
from decimal import Decimal
# Float → Double
java_double = convert_python_to_java(3.14159)
# Decimal → BigDecimal (for precision)
java_decimal = convert_python_to_java(Decimal("123.456789"))
# Reading with SQL parameter binding
with db.transaction():
db.command(
"sql",
"INSERT INTO Product SET price = ?, tax = ?",
19.99,
Decimal("1.23"),
)
row = db.query("sql", "SELECT price, tax FROM Product LIMIT 1").first()
price = row.get("price") # Double → float
tax = row.get("tax") # BigDecimal → Decimal
Strings¶
# String conversion with SQL parameter binding
with db.transaction():
db.command(
"sql",
"INSERT INTO User SET name = ?, emoji = ?",
"Alice",
"Hello 👋 World 🌍",
)
row = db.query("sql", "SELECT name, emoji FROM User LIMIT 1").first()
name = row.get("name") # String → str
emoji = row.get("emoji") # Full Unicode support
Dates and Times¶
from datetime import datetime, date, time
# datetime/date/time with SQL parameter binding
with db.transaction():
db.command(
"sql",
"INSERT INTO Event SET timestamp = ?, birthDate = ?, startTime = ?",
datetime.now(),
date(1990, 1, 15),
time(14, 30, 0),
)
row = db.query("sql", "SELECT timestamp, birthDate, startTime FROM Event LIMIT 1").first()
timestamp = row.get("timestamp") # datetime
birth_date = row.get("birthDate") # date
start_time = row.get("startTime") # time
Why some examples use set()
This page documents record property conversion behavior directly, so some examples use wrapper/property APIs to make the conversion boundary explicit. For normal application CRUD, prefer SQL/OpenCypher with bound parameters.
Binary Data¶
# bytes → byte[] (requires an active transaction)
binary_data = b"Hello World"
with db.transaction():
vertex = db.new_vertex("File")
vertex.set("data", binary_data)
# Reading back
data = vertex.get("data") # bytes
print(data.decode("utf-8")) # "Hello World"
Lists and Sets¶
# list → ArrayList (requires an active transaction)
with db.transaction():
vertex = db.new_vertex("User")
vertex.set("tags", ["python", "java", "database"])
tags = vertex.get("tags") # list
# set → HashSet
vertex.set("roles", {"admin", "user"})
roles = vertex.get("roles") # set
# Nested lists
vertex.set("matrix", [[1, 2], [3, 4]])
matrix = vertex.get("matrix") # [[1, 2], [3, 4]]
Dictionaries (Maps)¶
# dict → HashMap (requires an active transaction)
with db.transaction():
vertex = db.new_vertex("User")
vertex.set("profile", {
"firstName": "Alice",
"lastName": "Smith",
"address": {
"city": "New York",
"zip": "10001"
}
})
# Reading back
profile = vertex.get("profile") # dict
print(profile["firstName"]) # "Alice"
print(profile["address"]["city"]) # "New York"
Query Parameter Conversion¶
from datetime import datetime
# Query parameters are automatically converted
results = db.query(
"sql",
"SELECT FROM User WHERE age > ? AND createdAt > ?",
25, datetime(2024, 1, 1) # Python types converted to Java
)
results = db.query(
"sql",
"SELECT FROM User WHERE age IN :ages",
{"ages": [25, 30, 35]} # dict/list converted to Java Map/List
)
# Reading results (automatically converted back to Python)
for result in results:
name = result.get("name") # str
age = result.get("age") # int
created = result.get("createdAt") # datetime
Collection Type Preservation¶
# Lists preserve order (requires an active transaction)
with db.transaction():
vertex = db.new_vertex("Sequence")
vertex.set("numbers", [3, 1, 4, 1, 5, 9])
numbers = vertex.get("numbers") # [3, 1, 4, 1, 5, 9]
# Sets remove duplicates
vertex.set("unique", {3, 1, 4, 1, 5, 9})
unique = vertex.get("unique") # {1, 3, 4, 5, 9}
# Dicts preserve keys
vertex.set("mapping", {"a": 1, "b": 2, "c": 3})
mapping = vertex.get("mapping") # {"a": 1, "b": 2, "c": 3}
Complete Example¶
import arcadedb_embedded as arcadedb
from datetime import datetime, date
from decimal import Decimal
# Create database
db = arcadedb.create_database("./type_demo")
# Create schema (auto-transactional)
db.command("sql", "CREATE VERTEX TYPE Product")
# Test all type conversions
with db.transaction():
product = db.new_vertex("Product")
# Primitives
product.set("productId", 12345) # int
product.set("name", "Laptop") # str
product.set("inStock", True) # bool
product.set("price", 999.99) # float
product.set("tax", Decimal("50.00")) # Decimal
# Date/time
product.set("createdAt", datetime.now()) # datetime
product.set("releaseDate", date(2024, 1, 15)) # date
# Collections
product.set("tags", ["electronics", "laptop"]) # list
product.set("categories", {"computers", "tech"}) # set
# Nested structures
product.set("specs", {
"cpu": "Intel i7",
"ram": "16GB",
"storage": ["512GB SSD", "1TB HDD"]
}) # dict
# Binary
product.set("thumbnail", b"PNG\x89...") # bytes
product.save()
# Read back and verify types
results = list(db.query("sql", "SELECT FROM Product"))
product = results[0]
print(f"Product ID: {product.get('productId')} ({type(product.get('productId')).__name__})")
print(f"Name: {product.get('name')} ({type(product.get('name')).__name__})")
print(f"In Stock: {product.get('inStock')} ({type(product.get('inStock')).__name__})")
print(f"Price: {product.get('price')} ({type(product.get('price')).__name__})")
print(f"Tax: {product.get('tax')} ({type(product.get('tax')).__name__})")
print(f"Created At: {product.get('createdAt')} ({type(product.get('createdAt')).__name__})")
print(f"Tags: {product.get('tags')} ({type(product.get('tags')).__name__})")
db.close()
Output:
Product ID: 12345 (int)
Name: Laptop (str)
In Stock: True (bool)
Price: 999.99 (float)
Tax: 50.00 (Decimal)
Created At: 2024-01-15 10:30:45.123456 (datetime)
Tags: ['electronics', 'laptop'] (list)
Manual Conversion¶
Most of the time, conversions happen automatically. But you can manually convert when needed:
from arcadedb_embedded.type_conversion import convert_python_to_java, convert_java_to_python
# Manual Python → Java
python_data = {"name": "Alice", "age": 30}
java_map = convert_python_to_java(python_data)
# Use Java object directly (requires an active transaction)
with db.transaction():
java_record = db.new_vertex("User")._java_object
java_record.set("profile", java_map)
# Manual Java → Python
java_property = java_record.get("profile")
python_dict = convert_java_to_python(java_property)
print(python_dict) # {"name": "Alice", "age": 30}
Best Practices¶
1. Use Native Python Types¶
# ✅ Good: Use Python types
vertex.set("tags", ["python", "java"])
vertex.set("count", 42)
vertex.set("timestamp", datetime.now())
# ❌ Bad: Manually convert (unnecessary)
from arcadedb_embedded.type_conversion import convert_python_to_java
vertex.set("tags", convert_python_to_java(["python", "java"])) # Redundant
2. Use Decimal for Money¶
from decimal import Decimal
# ✅ Good: Decimal for precise values
vertex.set("price", Decimal("19.99"))
vertex.set("tax", Decimal("1.60"))
# ❌ Bad: Float for money (precision loss)
vertex.set("price", 19.99) # May lose precision
3. Consistent Collection Types¶
# ✅ Good: Consistent types
vertex.set("tags", ["tag1", "tag2", "tag3"]) # All strings
# ⚠️ Mixed types work but can be confusing
vertex.set("mixed", [1, "two", 3.0, True])
4. Handle None Values¶
# ✅ Good: Check for None
age = vertex.get("age")
if age is not None:
print(f"Age: {age}")
else:
print("Age not set")
# ❌ Bad: Assume value exists
print(f"Age: {vertex.get('age')}") # May be None
Type Conversion Limitations¶
1. Custom Python Classes¶
# ❌ Custom classes not supported
class MyClass:
def __init__(self, value):
self.value = value
vertex.set("custom", MyClass(42)) # ❌ Error
# ✅ Convert to dict first
vertex.set("custom", {"value": 42}) # ✅ Works
2. Complex Nested Structures¶
# ✅ Reasonable nesting works
vertex.set("data", {
"level1": {
"level2": {
"level3": [1, 2, 3]
}
}
})
# ⚠️ Very deep nesting may impact performance
3. Large Binary Data¶
# ✅ Small binary data
vertex.set("icon", b"PNG\x89...") # OK
# ⚠️ Large binary data (consider file storage)
with open("large_file.bin", "rb") as f:
data = f.read() # May be very large
vertex.set("file", data) # May impact memory
Troubleshooting¶
Type Mismatch Errors¶
# ❌ Error: Expected list, got dict
vertex.set("tags", {"tag1": 1}) # Wrong type
# ✅ Fix: Use correct type
vertex.set("tags", ["tag1"])
Precision Loss with Floats¶
# ⚠️ Float precision issues
price = 19.99
tax = 0.01
total = price + tax # May not be exactly 20.00
# ✅ Use Decimal
from decimal import Decimal
price = Decimal("19.99")
tax = Decimal("0.01")
total = price + tax # Exactly 20.00
Date/Time Timezone Issues¶
from datetime import datetime, timezone
# ⚠️ Naive datetime (no timezone)
now = datetime.now() # Local time, no timezone
# ✅ Aware datetime (with timezone)
now_utc = datetime.now(timezone.utc) # UTC time
See Also¶
- Database API - Database operations
- Queries Guide - Query parameters and usage
- Example 01: Document Store - Basic type usage
- Python JPype Documentation - Python-Java bridge