GitPedia

Java sproc wrapper

Java Stored Procedure Wrapper: Calling PostgreSQL stored procedures from Java

From zalando-stups·Updated May 16, 2026·View on GitHub·

Library to make PostgreSQL stored procedures(SProcs) available through simple Java "SProcService" interfaces including automatic object serialization and deserialization (using typemapper and convention-over-configuration). The project is written primarily in Java, distributed under the MIT License license, first published in 2012. Key topics include: hacktoberfest, java, postgresql, proxy, rpc.

Latest release: 4.0.0
October 14, 2025View Changelog →

SProcWrapper

Build Status Coverage Status
Javadoc
Maven Central
License

Library to make PostgreSQL stored procedures(SProcs) available through simple Java "SProcService" interfaces including
automatic object serialization and deserialization (using typemapper and convention-over-configuration).

Supports horizontal database sharding (partition/access logic lies within application), easy use of pg_advisory_lock
through annotations to ensure single Java node execution, configurable statement timeouts per stored procedure, and
PostgreSQL types including enums and hstore.

Usage

To use SProcWrapper, add the following lines to your pom.xml:

xml
<dependency> <groupId>org.zalando</groupId> <artifactId>zalando-sprocwrapper</artifactId> <version>${zalando-sprocwrapper.version}</version> </dependency>

Type Mapping

SProcWrapper provides an efficient and easy-to-use mechanism for translating values from database to Java objects and
vice-versa. It allows us to map not only primitive types, but also complex types (Java domain objects).

Here are some examples!

Using basic types:

java
@SProcService public interface CustomerSProcService { @SProcCall int registerCustomer(@SProcParam String name, @SProcParam String email); }
sql
CREATE FUNCTION register_customer(p_name TEXT, p_email TEXT) RETURNS INT AS $$ INSERT INTO z_data.customer(c_name, c_email) VALUES (p_name, p_email) RETURNING c_id $$ LANGUAGE 'sql' SECURITY DEFINER;

And a complex type:

java
@SProcService public interface OrderSProcService { @SProcCall List<Order> findOrders(@SProcParam String email); }
sql
CREATE FUNCTION find_orders(p_email TEXT, OUT order_id INT, OUT order_date TIMESTAMP, OUT shipping_address ORDER_ADDRESS) RETURNS SETOF RECORD AS $$ SELECT o_id, o_date, ROW (oa_street, oa_city, oa_country)::ORDER_ADDRESS FROM z_data.order JOIN z_data.order_address ON oa_order_id = o_id JOIN z_data.customer ON c_id = o_customer_id WHERE c_email = p_email $$ LANGUAGE 'sql' SECURITY DEFINER;

Please check unit/integration tests for more examples.

The following table shows the mapping between a database type and a Java type:

DatabaseJava Type
smallintint
integerint
bigintlong
decimaljava.math.BigDecimal
numericjava.math.BigDecimal
realfloat
double precisiondouble
serialint
bigseriallong
varcharjava.lang.String
charchar
textjava.lang.String
timestampjava.sql.Timestamp
timestamptzjava.sql.Timestamp
datejava.sql.Timestamp
timejava.sql.Timestamp
timetzjava.sql.Timestamp
booleanboolean
enumjava.lang.Enum
arrayjava.util.List / java.util.Set
hstorejava.util.Map<java.lang.String, java.lang.String>

Note: SProcwrapper doesn't support functions returning arrays as a single output. If one wants to return a collection,
please return a SETOF instead.

Configure global value transformer loader

Global value transformer loader loads global value transformers from the classpath. By default, it searches value
transformers in org.zalando package. You can change this behaviour using
the global.value.transformer.search.namespace environment variable:

shell
EXPORT global.value.transformer.search.namespace="my.package"

or by calling a method:

java
GlobalValueTransformerLoader.changeNamespaceToScan("my.package");

It is also possible to provide multiple scan packages using ; separator:

shell
EXPORT global.value.transformer.search.namespace="my.package;another.package;third.package"

Prerequisites

  • Java 17
  • To compile, one should use Maven 3.0.0 or above

Dependencies

  • Spring Framework 5.x
  • PostgreSQL JDBC driver ;)
  • Google Guava

See pom.xml for the full list of dependencies.

How to run integration tests

The provided helper script will start a PostgreSQL instance with Docker on port 5432 and run integration tests:

shell
./test.sh

Known issues

  • PostgreSQL JDBC driver does not honor identical type names in different schemas, this may lead to issues if typemapper
    is used where types are present with equal name in more than one schema (this problem is solved now with the
    commit 3ca94e64d6322fa91c477200bfb3719deaeac153
    to pgjdbc driver);
  • PostgreSQL domains are not supported as for now;
  • PostgreSQL hstore type is mapped from and to Map<String,String>, there is no way to use Map of different types
    for now;
  • Two different datasources with the same JDBC URL and different search paths might not work properly when we have types
    with the identical name;
  • SProcWrapper relies on the search path to resolve conflicting types with the same name (right now, we are not checking
    the schema). If one specifies the schema of the stored procedure's return type, SProcWrapper might end up using the
    wrong one, because it will use the search_path to resolve the conflict. For more info check
    test: SimpleIT.testTypeLookupBugWithSchema;
  • For integration with Spring's transaction management use the TransactionAwareDataSourceProxy as the data source
    injected into the data source provider.

Documentation

You can find some more information about the SProcWrapper in our various Zalando Technology blog posts:

🚨 Upgrading from 2.x to 3.x? Please be aware that default scanning package for custom objectTransformer has changed from de.zalando to org.zalando.

Contributing

See contributing guideline.

License

MIT license. See license file.

Contributors

Showing top 12 contributors by commit count.

View all contributors on GitHub →

This article is auto-generated from zalando-stups/java-sproc-wrapper via the GitHub API.Last fetched: 6/27/2026