{"id":13792677,"url":"https://github.com/tarantool/tarantool-java","last_synced_at":"2025-05-12T14:32:03.036Z","repository":{"id":11516433,"uuid":"13997496","full_name":"tarantool/tarantool-java","owner":"tarantool","description":"A Java client for Tarantool","archived":false,"fork":true,"pushed_at":"2023-01-12T03:29:40.000Z","size":3316,"stargazers_count":51,"open_issues_count":64,"forks_count":18,"subscribers_count":27,"default_branch":"master","last_synced_at":"2024-12-22T18:05:13.805Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://tarantool.org","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"dork/tarantool-java","license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tarantool.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-30T19:38:35.000Z","updated_at":"2024-11-15T22:59:53.000Z","dependencies_parsed_at":"2023-01-16T20:15:36.064Z","dependency_job_id":null,"html_url":"https://github.com/tarantool/tarantool-java","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Ftarantool-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Ftarantool-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Ftarantool-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Ftarantool-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tarantool","download_url":"https://codeload.github.com/tarantool/tarantool-java/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253754968,"owners_count":21958934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T22:01:14.976Z","updated_at":"2025-05-12T14:32:02.480Z","avatar_url":"https://github.com/tarantool.png","language":"Java","readme":"\u003ca href=\"http://tarantool.org\"\u003e\n   \u003cimg src=\"https://avatars2.githubusercontent.com/u/2344919?v=2\u0026s=250\"\nalign=\"right\"\u003e\n\u003c/a\u003e\n\n# Deprecation note\n\nThis connector is not in the active development and de facto deprecated.\nConsider using the modern alternatives: [cartridge-java][cartridge-java] and\n[cartridge-springdata][cartridge-springdata]. It is based on Netty framework\nand supports single node/cluster queries.\n\nYou may be still interesting in tarantool-java connector if you're using\nTarantool via JDBC.\n\n[cartridge-java]: https://github.com/tarantool/cartridge-java\n[cartridge-springdata]: https://github.com/tarantool/cartridge-springdata\n\n# Java connector for Tarantool\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.tarantool/connector/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.tarantool/connector)\n[![Build Status](https://travis-ci.org/tarantool/tarantool-java.svg?branch=master)](https://travis-ci.org/tarantool/tarantool-java)\n[![Coverage Status](https://coveralls.io/repos/github/tarantool/tarantool-java/badge.svg?branch=master)](https://coveralls.io/github/tarantool/tarantool-java?branch=master)\n\nTo get the Java connector for Tarantool 1.6.9, visit\n[this GitHub page](https://github.com/tarantool/tarantool-java/tree/connector-1.6.9).\n\n## Table of contents\n* [Getting started](#getting-started)\n* [Spring NamedParameterJdbcTemplate usage example](#spring-namedparameterjdbctemplate-usage-example)\n* [JDBC](#JDBC)\n* [Cluster support](#cluster-support)\n* [Logging](#logging)\n* [Building](#building)\n* [Where to get help](#where-to-get-help)\n\n## Getting started\n\n1. Add a dependency to your `pom.xml` file (look for a last version on the\n   [releases page](https://github.com/tarantool/tarantool-java/releases)):\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.tarantool\u003c/groupId\u003e\n  \u003cartifactId\u003econnector\u003c/artifactId\u003e\n  \u003cversion\u003e1.9.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2. Configure `TarantoolClientConfig`:\n\n```java\nTarantoolClientConfig config = new TarantoolClientConfig();\nconfig.username = \"test\";\nconfig.password = \"test\";\n```\n\n3. Create a client:\n\n```java\nTarantoolClient client = new TarantoolClientImpl(\"host:3301\", config);\n```\n\nusing `TarantoolClientImpl(String, TarantoolClientConfig)` is equivalent to:\n\n```java\nSocketChannelProvider socketChannelProvider = new SingleSocketChannelProviderImpl(\"host:3301\")\nTarantoolClient client = new TarantoolClientImpl(socketChannelProvider, config);\n```\n\nYou could implement your own `SocketChannelProvider`. It should return \na connected `SocketChannel`. Feel free to implement `get(int retryNumber, Throwable lastError)`\nusing your appropriate strategy to obtain the channel. The strategy can take into\naccount current attempt number (retryNumber) and the last transient error occurred on\nthe previous attempt.\n\nThe `TarantoolClient` will be closed if your implementation of a socket\nchannel provider raises exceptions. However, throwing a `SocketProviderTransientException`\nor returning `null` value are handled by the client as recoverable errors. In these cases,\nthe client will make next attempt to obtain the socket channel. Otherwise, you will need\na new instance of client to recover. Hence, you should only throw an error different\nto `SocketProviderTransientException` in case you have met unrecoverable error.\n\nBelow is an example of `SocketChannelProvider` implementation that tries\nto connect no more than 3 times, two seconds for each attempt at max.\n\n```java\nSocketChannelProvider socketChannelProvider = new SocketChannelProvider() {\n    @Override\n    public SocketChannel get(int retryNumber, Throwable lastError) {\n        if (retryNumber \u003e 3) {\n            throw new RuntimeException(\"Too many attempts\");\n        }\n        SocketChannel channel = null;\n        try {\n            channel = SocketChannel.open();\n            channel.socket().connect(new InetSocketAddress(\"localhost\", 3301), 2000);\n            return channel;\n        } catch (IOException e) {\n            if (channel != null) {\n                 try {\n                     channel.close();\n                 } catch (IOException ignored) { }\n            }\n            throw new SocketProviderTransientException(\"Couldn't connect to server\", e);\n        }\n    }\n};\n```\n\nSame behaviour can be achieved using built-in `SingleSocketChannelProviderImpl`:\n\n```java\nTarantoolClientConfig config = new TarantoolClientConfig();\nconfig.connectionTimeout = 2_000; // two seconds timeout per attempt\nconfig.retryCount = 3;            // three attempts at max\n\nSocketChannelProvider socketChannelProvider = new SingleSocketChannelProviderImpl(\"localhost:3301\")\nTarantoolClient client = new TarantoolClientImpl(socketChannelProvider, config);\n```\n\n`SingleSocketChannelProviderImpl` implements `ConfigurableSocketChannelProvider` that\nmakes possible for the client to configure a socket provider.\n\n\u003e **Notes:**\n\u003e * `TarantoolClient` is thread-safe and asynchronous, so you should use one\n\u003e   client inside the whole application.\n\u003e * `TarantoolClient` does not support name resolution for fields, indexes,\n\u003e   spaces and so on. We highly recommend to use server-side Lua when working\n\u003e   with named items. For example, you could create a data access object (DAO)\n\u003e   with simple CRUD functions. If, for some reason, you do need client name\n\u003e   resolution, you could create a function that returns necessary name-to-ID\n\u003e   mappings.\n\n`TarantoolClient` provides four interfaces to execute queries:\n\n* `SyncOps` - returns the operation result\n* `AsyncOps` - returns the operation result as a `Future`\n* `ComposableAsyncOps` - return the operation result as a `CompletionStage`\n* `FireAndForgetOps` - returns the query ID\n\nFeel free to override any method of `TarantoolClientImpl`. For example, to hook\nall the results, you could override this:\n\n```java\nprotected void complete(TarantoolPacket packet, CompletableFuture\u003c?\u003e future);\n```\n\n### Client config options\n\nThe client configuration options are represented through the `TarantoolClientConfig` class.\n\nSupported options are follow:\n\n1. `username` is used to authenticate and authorize an user in a Taratool server instance.\n   Default value is `null` that means client will attempt to auth as a *guest*.\n2. `password` is used to authenticate an user in a Taratool server instance.\n   Default value is `null`.\n3. `defaultRequestSize` used to be an initial binary buffer size in bytes to send requests.\n   Default value is `4096` (4 KB).\n4. `predictedFutures` is used to initialize an initial capacity of hash map which stores\n   response futures. The client is asynchronous under the hood even though it provides\n   a synchronous operations using `java.concurrent.CompletableFuture`.\n   Default value is `(1024 * 1024) / 0.75) + 1`.\n5. `writerThreadPriority` describes a priority of writer thread.\n   Default value is `Thread.NORM_PRIORITY` (5).\n6. `readerThreadPriority` describes a priority of reader thread.\n   Default value is `Thread.NORM_PRIORITY` (5).\n7. `sharedBufferSize` sets a shared buffer size in bytes (place where client collects\n   requests when socket is busy on write).\n   Default value is `8 * 1024 * 1024` (8 MB).\n8. `directWriteFactor` is used as a factor to calculate a threshold whether\n   request will be accommodated in the shared buffer. If the request size exceeds\n   `directWriteFactor * sharedBufferSize` request is sent directly.\n   Default value is `0.5`.\n9. `writeTimeoutMillis` sets the max time in ms to perform writing and send the bytes.\n    Default value is 60 * 1000 (1 minute).\n10. `useNewCall` configures whether client has to use new *CALL* request signature or old\n    one used to be active in Tarantool 1.6.\n    Default value is `true`.\n11. `initTimeoutMillis` sets a max time in ms to establish connection to the server\n    Default values is `60 * 1000L` (1 minute).\n12. `connectionTimeout` is a hint and can be passed to the socket providers which\n    implement `ConfigurableSocketChannelProvider` interface. This hint should be\n    interpreter as a connection timeout in ms per attempt where `0` means no limit.\n    This options restricts a time budget to perform one connection attempt, while\n    `initTimeoutMillis` limits an overall time to obtain a connection.\n    Default value is `2 * 1000` (2 seconds).\n13. `retryCount` is a hint and can be passed to the socket providers which\n    implement `ConfigurableSocketChannelProvider` interface. This hint should be\n    interpreter as a maximal number of attempts to connect to Tarantool instance.\n    Default value is `3`.  \n14. `operationExpiryTimeMillis` is a default request timeout in ms.\n    Default value is `1000` (1 second).\n\n## String space/index resolution\n\nEach operation that requires space or index to be executed, can work with\nnumber ID as well as string name of a space or an index.\nAssume, we have `my_space` space with space ID `512` and its primary index\n`primary` with index ID `0`. Then, for instance, `select` operations can be\nperformed using their names:\n\n```java\nclient.syncOps().select(512, 0, Collections.singletonList(1), 0, 1, Iterator.EQ);\n// or using more convenient way\nclient.syncOps().select(\"my_space\", \"primary\", Collections.singletonList(1), 0, 1, Iterator.EQ);\n```\n\nBecause _iproto_ has not yet supported string spaces and indexes, a client caches current server\nschema in memory. The client relies on protocol SCHEMA_ID and sends each request with respect to\ncached schema version. The schema is used primarily to resolve string names of spaces or indexes\nagainst its integer IDs.\n\n### Schema update\n\n1. Just after a (re-)connection to the Tarantool instance.\n   The client cannot guarantee that new instance is the same and has same schema,\n   thus, the client drops the cached schema and fetches new one.\n2. Receiving a schema version error as a response to our request.\n   It's possible some request can be rejected by server because of schema\n   mismatching between client and server. In this case the schema will be\n   reloaded and the refused request will be resent using the updated schema\n   version.\n3. Sending a DDL request and receiving a new version in a response.\n4. Sending a request against a non-existent space/index name.\n   The client cannot exactly know whether name was not found because of\n   it does not exist or it has not the latest schema version. A ping request\n   is sent in the case to check a schema version and then a client will reload\n   it if needed. The original request will be retried if a space / an index\n   name will be found in a new schema.\n\n### Schema support caveats\n\n1. Each schema reloading requires at least two extra requests to fetch spaces and\n   indexes metadata respectively. There is also a ping request followed by reloading\n   of the schema to check whether the client has outdated version (see point 4 in\n   [Schema update](#schema-update)).\n2. In some circumstance, requests can be rejected several times until both client's\n   and server's versions matches. It may take significant amount of time or even be\n   a cause of request timeout.\n3. The client guarantees an order of synchronous requests per thread. Other cases such\n   as asynchronous or multi-threaded requests may be out of order before the execution.\n\n## Spring NamedParameterJdbcTemplate usage example\n\nThe JDBC driver uses `TarantoolClient` implementation to provide a communication with server.\nTo configure socket channel provider you should implements SocketChannelProvider and add\n`socketChannelProvider=abc.xyz.MySocketChannelProvider` to connect url.\n\nFor example:\n\n```\njdbc:tarantool://localhost:3301?user=test\u0026password=test\u0026socketProvider=abc.xyz.MySocketProvider\n```\n\nHere is an example how you can use the driver covered by Spring `DriverManagerDataSource`:\n\n```java\nNamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(new DriverManagerDataSource(\"jdbc:tarantool://localhost:3301?user=test\u0026password=test\"));\nRowMapper\u003cObject\u003e rowMapper = new RowMapper\u003cObject\u003e() {\n    @Override\n    public Object mapRow(ResultSet resultSet, int i) throws SQLException {\n        return Arrays.asList(resultSet.getInt(1), resultSet.getString(2));\n    }\n};\n\ntry {\n    System.out.println(template.update(\"drop table hello_world\", Collections.\u003cString, Object\u003eemptyMap()));\n} catch (Exception ignored) {\n}\n\nSystem.out.println(template.update(\"create table hello_world(hello int not null PRIMARY KEY, world varchar(255) not null)\", Collections.\u003cString, Object\u003eemptyMap()));\nMap\u003cString, Object\u003e params = new LinkedHashMap\u003cString, Object\u003e();\nparams.put(\"text\", \"hello world\");\nparams.put(\"id\", 1);\n\nSystem.out.println(template.update(\"insert into hello_world(hello, world) values(:id,:text)\", params));\nSystem.out.println(template.query(\"select * from hello_world\", rowMapper));\n\nSystem.out.println(template.query(\"select * from hello_world where hello=:id\", Collections.singletonMap(\"id\", 1), rowMapper));\n```\n\nFor more implementation details, see [API documentation](http://tarantool.github.io/tarantool-java/apidocs/index.html).\n\n## JDBC\n\n### Batch updates\n\n`Statement` and `PreparedStatement` objects can be used to submit batch\nupdates.\n\nFor instance, using `Statement` object:\n\n```java\nStatement statement = connection.createStatement();\nstatement.addBatch(\"INSERT INTO student VALUES (30, 'Joe Jones')\");\nstatement.addBatch(\"INSERT INTO faculty VALUES (2, 'Faculty of Chemistry')\");\nstatement.addBatch(\"INSERT INTO student_faculty VALUES (30, 2)\");\n\nint[] updateCounts = stmt.executeBatch();\n```\n\nor using `PreparedStatement`:\n\n```java\nPreparedStatement stmt = con.prepareStatement(\"INSERT INTO student VALUES (?, ?)\");\nstmt.setInt(1, 30);\nstmt.setString(2, \"Michael Korj\");\nstmt.addBatch();\nstmt.setInt(1, 40);\nstmt.setString(2, \"Linda Simpson\");\nstmt.addBatch();\n\nint[] updateCounts = stmt.executeBatch();\n```\n\nThe connector uses a pipelining when it performs a batch request. It means\neach query is asynchronously sent one-by-one in order they were specified\nin the batch.\n\nThere are a couple of caveats:\n\n- JDBC spec recommends that *auto-commit* mode should be turned off\nto prevent the driver from committing a transaction when a batch request\nis called. The connector is not support transactions and *auto-commit* is\nalways enabled, so each statement from the batch is executed in its own\ntransaction.\n\n- DDL operations aren't transactional in Tarantool. In this way, a batch\nlike this can produce an undefined behaviour (i.e. second statement can fail\nwith an error that `student` table does not exist).\n\n```java\nstatement.addBatch(\"CREATE TABLE student (id INT PRIMARY KEY, name VARCHAR(100))\");\nstatement.addBatch(\"INSERT INTO student VALUES (1, 'Alex Smith')\");\n```\n\n- If `vinyl` storage engine is used an execution order of batch statements is\nnot specified. __NOTE:__ This behaviour is incompatible with JDBC spec in the\nsentence \"Batch commands are executed serially (at least logically) in the\norder in which they were added to the batch\"\n\n- The driver continues processing the remaining commands in a batch once execution\nof a command fails.\n\n## Cluster support\n\nTo be more fault-tolerant the connector provides cluster extensions. In\nparticular `TarantoolClusterClient` and built-in `RoundRobinSocketProviderImpl`\nused as a default `SocketProvider` implementation. When currently connected\ninstance is down then the client will try to reconnect to the first available\ninstance using strategy defined in a socket provider. You need to supply\na list of nodes which will be used by the cluster client to provide such\nability. Also you can prefer to use a [discovery mechanism](#auto-discovery)\nin order to dynamically fetch and apply the node list.\n\n### The RoundRobinSocketProviderImpl class\n\nThis cluster-aware provider uses addresses pool to connect to DB server.\nThe provider picks up next address in order the addresses were passed.\n\nSimilar to `SingleSocketChannelProviderImpl` this RR provider also\nrelies on two options from the config: `TarantoolClientConfig.connectionTimeout`\nand `TarantoolClientConfig.retryCount` but in a bit different way.\nThe latter option says how many times the provider should try to establish a\nconnection to _one instance_ before failing an attempt. The provider requires\npositive retry count to work properly. The socket timeout is used to limit\nan interval between connections attempts per instance. In other words, the provider\nfollows a pattern _connection should succeed after N attempts with M interval between\nthem at max_. \n\n### Basic cluster client usage\n\n1. Configure `TarantoolClusterClientConfig`:\n\n```java\nTarantoolClusterClientConfig config = new TarantoolClusterClientConfig();\n// fill other settings\nconfig.operationExpiryTimeMillis = 2000;\nconfig.executor = Executors.newSingleThreadExecutor();\n```\n\n2. Create an instance of `TarantoolClusterClientImpl`. You need to provide\nan initial list of nodes:\n\n```java\nString[] nodes = new String[] { \"myHost1:3301\", \"myHost2:3302\", \"myHost3:3301\" };\nTarantoolClusterClient client = new TarantoolClusterClient(config, nodes);\n``` \n\n3. Work with the client using same API as defined in `TarantoolClient`:\n\n```java\nclient.syncOps().insert(23, Arrays.asList(1, 1));\n```\n\n### Auto-discovery\n\nAuto-discovery feature allows a cluster client to fetch addresses of \ncluster nodes to reflect changes related to the cluster topology. To achieve\nthis you have to create a Lua function on the server side which returns \na single array result. Client periodically polls the server to obtain a \nfresh list and apply it if its content changes.\n\n1. On the server side create a function which returns nodes:\n\n```bash\ntarantool\u003e function get_cluster_nodes() return { 'host1:3301', 'host2:3302', 'host3:3301' } end\n```\n\nYou need to pay attention to a function contract we are currently supporting:\n* The client never passes any arguments to a discovery function.\n* A discovery function _must_ return an array of strings (i.e `return {'host1:3301', 'host2:3301'}`).\n* Each string _should_ satisfy the following pattern `host[:port]`\n  (or more strictly `/^[^:]+(:\\d+)?$/` - a mandatory host containing any string\n  and an optional colon followed by digits of the port). Also, the port must be\n  in a range between 1 and 65535 if one is presented.\n* A discovery function _may_ return multi-results but the client takes\n  into account only first of them (i.e. `return {'host:3301'}, discovery_delay`, where \n  the second result is unused). Even more, any extra results __are reserved__ by the client\n  in order to extend its contract with a backward compatibility.\n* A discovery function _should NOT_ return no results, empty result, wrong type result,\n  and Lua errors. The client discards such kinds of results but it does not affect the discovery\n  process for next scheduled tasks. \n\n2. On the client side configure discovery settings in `TarantoolClusterClientConfig`:\n\n```java\nTarantoolClusterClientConfig config = new TarantoolClusterClientConfig();\n// fill other settings\nconfig.clusterDiscoveryEntryFunction = \"get_cluster_nodes\"; // discovery function used to fetch nodes \nconfig.clusterDiscoveryDelayMillis = 60_000;                // how often client polls the discovery server  \n```\n\n3. Create a client using the config made above.\n\n```java\nTarantoolClusterClient client = new TarantoolClusterClient(config);\nclient.syncOps().insert(45, Arrays.asList(1, 1));\n```\n\n### Auto-discovery caveats\n\n* You need to set _not empty_ value to `clusterDiscoveryEntryFunction` to enable auto-discovery feature.\n* There are only two cases when a discovery task runs: just after initialization of the cluster\n  client and a periodical scheduler timeout defined in `TarantoolClusterClientConfig.clusterDiscoveryDelayMillis`. \n* A discovery task always uses an active client connection to get the nodes list.\n  It's in your responsibility to provide a function availability as well as a consistent\n  nodes list on all instances you initially set or obtain from the task.\n* Every address which is unmatched with `host[:port]` pattern will be filtered out from\n  the target addresses list.\n* If some error occurs while a discovery task is running then this task\n  will be aborted without any after-effects for next task executions. These cases, for instance, are \n  a wrong function result (see discovery function contract) or a broken connection. \n  There is an exception if the client is closed then discovery process will stop permanently.\n* It's possible to obtain a list which does NOT contain the node we are currently\n  connected to. It leads the client to try to reconnect to another node from the \n  new list. It may take some time to graceful disconnect from the current node.\n  The client does its best to catch the moment when there are no pending responses\n  and perform a reconnection.  \n\n### Cluster client config options\n\nIn addition to the options for [the standard client](#client-config-options), cluster\nconfig provides some extra options:\n\n1. `executor` defines an executor that will be used as a thread of execution to retry writes.\n   Default values is `null` which means the cluster client will use *a single thread executor*.\n2. `clusterDiscoveryEntryFunction` is a name of the stored function to be used to fetch list of\n   instances.\n   Default value is `null` (not set).\n3. `clusterDiscoveryDelayMillis` describes how often in ms to poll the server for a new list of\n   cluster nodes.\n   Default value is `60 * 1000` (1 minute).\n\n## Logging\n\nThe connector uses its own logging facade to abstract from any logging libraries\nwhich can be used inside the apps where the connector attached. At the moment,\nthe facade supports JUL as a default logging system, SLF4J facade, and Logback\ndirectly via SLF4J interface.\n\n### Logging integration\n\nThe logging facade offers several ways in integrate its internal logging with foreign one in order:\n\n* Using system property `org.tarantool.logging.provider`. Supported values are *jdk* and *slf4j*\n  for the java util logging and SLF4J/Logback respectively. For instance, use \n  `java -Dorg.tarantool.logging.provider=slf4j \u003c...\u003e`.\n\n* Using Java SPI mechanism. Implement your own provider org.tarantool.logging.LoggerProvider\n  To register your provider save `META-INF.services/org.tarantool.logging.LoggerProvider` file\n  with a single line text contains a fully-qualified class name of the provider implementation.\n\n```bash\ncat META-INF/services/org.tarantool.logging.LoggerProvider\norg.mydomain.MySimpleLoggerProvider\n```\n\n* CLASSPATH exploring. Now, the connector will use SLF4J if Logback is also in use. \n\n* If nothing is successful JUL will be used by default.\n\n### Supported loggers\n\n| Logger name                                    | Level | Description                                       |\n| ---------------------------------------------- | ----- | ------------------------------------------------- |\n| o.t.c.TarantoolClusterStoredFunctionDiscoverer | WARN  | prints out invalid discovery addresses            |\n| o.t.TarantoolClusterClient                     | TRACE | prints out request retries after transient errors |\n| o.t.TarantoolClientImpl                        | WARN  | prints out reconnect issues                       |\n\n## Building\n\nTo run unit tests use:\n \n```bash\n./mvnw clean test\n``` \n\nTo run integration tests use:\n\n```bash\n./mvnw clean verify\n```\n\n## Where to get help\n\nGot problems or questions? Post them on\n[Stack Overflow](http://stackoverflow.com/questions/ask/advice) with the\n`tarantool` and `java` tags, or use these tags to search the existing knowledge\nbase for possible answers and solutions.\n","funding_links":[],"categories":["II. Databases, search engines, big data and machine learning","Connectors"],"sub_categories":["4. Client and drivers for databases","Administration"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Ftarantool-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarantool%2Ftarantool-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Ftarantool-java/lists"}