Skip to content

Commit e42a554

Browse files
committed
chore: add Java wrapper for SpannerLib
Adds a Java wrapper for SpannerLib and some simple tests for this wrapper.
1 parent bbdea73 commit e42a554

File tree

17 files changed

+885
-0
lines changed

17 files changed

+885
-0
lines changed

.github/workflows/spanner-lib-tests.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,51 @@ jobs:
2323
- name: Run unit tests
2424
working-directory: spannerlib
2525
run: go test ./... -race -short
26+
27+
java-wrapper:
28+
strategy:
29+
matrix:
30+
go-version: [1.25.x]
31+
os: [ubuntu-latest, macos-latest, windows-latest]
32+
runs-on: ${{ matrix.os }}
33+
steps:
34+
- name: Install Java
35+
uses: actions/setup-java@v4
36+
with:
37+
distribution: temurin
38+
java-version: 21
39+
- name: Checkout code
40+
uses: actions/checkout@v4
41+
- name: Check Java formatting
42+
run: mvn com.spotify.fmt:fmt-maven-plugin:check
43+
working-directory: spannerlib/wrappers/spannerlib-java
44+
- name: Install Go
45+
uses: actions/setup-go@v5
46+
with:
47+
go-version: ${{ matrix.go-version }}
48+
- name: Build shared library
49+
working-directory: spannerlib/shared
50+
run: go build -o spannerlib.so -buildmode=c-shared shared_lib.go
51+
- name: Copy to Java wrapper
52+
working-directory: spannerlib
53+
run: |
54+
echo "$RUNNER_OS"
55+
if [ "$RUNNER_OS" == "Windows" ]; then
56+
mkdir -p wrappers/spannerlib-java/src/main/resources/win32-x86-64
57+
cp shared/spannerlib.so wrappers/spannerlib-java/src/main/resources/win32-x86-64/spanner.dll
58+
elif [ "$RUNNER_OS" == "macOS" ]; then
59+
mkdir -p wrappers/spannerlib-java/src/main/resources/darwin-aarch64
60+
cp shared/spannerlib.so wrappers/spannerlib-java/src/main/resources/darwin-aarch64/libspanner.dylib
61+
else
62+
mkdir -p wrappers/spannerlib-java/src/main/resources/linux-x86-64
63+
cp shared/spannerlib.so wrappers/spannerlib-java/src/main/resources/linux-x86-64/libspanner.so
64+
fi
65+
shell: bash
66+
- name: ls spannerlib.so
67+
working-directory: spannerlib/wrappers/spannerlib-java/src/main/resources
68+
run: ls -lha
69+
shell: bash
70+
- name: Run Java tests
71+
run: mvn -Djna.debug_load=true test
72+
working-directory: spannerlib/wrappers/spannerlib-java
73+
shell: bash
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### IntelliJ IDEA ###
7+
.idea/modules.xml
8+
.idea/jarRepositories.xml
9+
.idea/compiler.xml
10+
.idea/libraries/
11+
*.iws
12+
*.iml
13+
*.ipr
14+
15+
### Eclipse ###
16+
.apt_generated
17+
.classpath
18+
.factorypath
19+
.project
20+
.settings
21+
.springBeans
22+
.sts4-cache
23+
24+
### NetBeans ###
25+
/nbproject/private/
26+
/nbbuild/
27+
/dist/
28+
/nbdist/
29+
/.nb-gradle/
30+
build/
31+
!**/src/main/**/build/
32+
!**/src/test/**/build/
33+
34+
### VS Code ###
35+
.vscode/
36+
37+
### Mac OS ###
38+
.DS_Store
39+
40+
# SpannerLib builds
41+
spannerlib.so
42+
spannerlib.dll
43+
libspanner.dylib
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
^/\*$
2+
^ \* Copyright \d\d\d\d,? Google (Inc\.|LLC)$
3+
^ \*$
4+
^ \* Licensed under the Apache License, Version 2\.0 \(the "License"\);$
5+
^ \* you may not use this file except in compliance with the License\.$
6+
^ \* You may obtain a copy of the License at$
7+
^ \*$
8+
^ \*[ ]+https?://www.apache.org/licenses/LICENSE-2\.0$
9+
^ \*$
10+
^ \* Unless required by applicable law or agreed to in writing, software$
11+
^ \* distributed under the License is distributed on an "AS IS" BASIS,$
12+
^ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.$
13+
^ \* See the License for the specific language governing permissions and$
14+
^ \* limitations under the License\.$
15+
^ \*/$
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<!DOCTYPE module PUBLIC
3+
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
4+
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
5+
<module name="Checker">
6+
<module name="RegexpHeader">
7+
<property name="fileExtensions" value="java"/>
8+
<property name="headerFile" value="${checkstyle.header.file}"/>
9+
</module>
10+
</module>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>org.example</groupId>
8+
<artifactId>spannerlib-java</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<maven.compiler.source>8</maven.compiler.source>
13+
<maven.compiler.target>8</maven.compiler.target>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
<parent>
17+
<groupId>com.google.cloud</groupId>
18+
<artifactId>sdk-platform-java-config</artifactId>
19+
<version>3.52.1</version>
20+
</parent>
21+
<dependencyManagement>
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.google.cloud</groupId>
25+
<artifactId>google-cloud-spanner-bom</artifactId>
26+
<version>6.100.0</version>
27+
<type>pom</type>
28+
<scope>import</scope>
29+
</dependency>
30+
</dependencies>
31+
</dependencyManagement>
32+
33+
<dependencies>
34+
<dependency>
35+
<groupId>com.google.api.grpc</groupId>
36+
<artifactId>proto-google-cloud-spanner-v1</artifactId>
37+
</dependency>
38+
<!-- Dependencies for using C library -->
39+
<dependency>
40+
<groupId>net.java.dev.jna</groupId>
41+
<artifactId>jna</artifactId>
42+
<version>5.17.0</version>
43+
</dependency>
44+
45+
<!-- Test dependencies -->
46+
<dependency>
47+
<groupId>com.google.cloud</groupId>
48+
<artifactId>google-cloud-spanner</artifactId>
49+
<scope>test</scope>
50+
</dependency>
51+
<dependency>
52+
<groupId>com.google.cloud</groupId>
53+
<artifactId>google-cloud-spanner</artifactId>
54+
<type>test-jar</type>
55+
<scope>test</scope>
56+
</dependency>
57+
<dependency>
58+
<groupId>com.google.api</groupId>
59+
<artifactId>gax-grpc</artifactId>
60+
<classifier>testlib</classifier>
61+
<scope>test</scope>
62+
<version>2.70.0</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>junit</groupId>
66+
<artifactId>junit</artifactId>
67+
<version>4.13.2</version>
68+
<scope>test</scope>
69+
</dependency>
70+
</dependencies>
71+
</project>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spannerlib;
18+
19+
import com.google.cloud.spannerlib.internal.SpannerLibrary;
20+
21+
/**
22+
* {@link AbstractLibraryObject} is the base class for all objects that are created by SpannerLib,
23+
* such as {@link Pool} and {@link Connection}.
24+
*/
25+
abstract class AbstractLibraryObject implements AutoCloseable {
26+
private final SpannerLibrary library;
27+
private final long id;
28+
29+
AbstractLibraryObject(SpannerLibrary library, long id) {
30+
this.library = library;
31+
this.id = id;
32+
}
33+
34+
SpannerLibrary getLibrary() {
35+
return this.library;
36+
}
37+
38+
long getId() {
39+
return this.id;
40+
}
41+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spannerlib;
18+
19+
import static com.google.cloud.spannerlib.internal.SpannerLibrary.executeAndRelease;
20+
21+
/** A {@link Connection} that has been created by SpannerLib. */
22+
public class Connection extends AbstractLibraryObject {
23+
private final Pool pool;
24+
25+
Connection(Pool pool, long id) {
26+
super(pool.getLibrary(), id);
27+
this.pool = pool;
28+
}
29+
30+
public Pool getPool() {
31+
return this.pool;
32+
}
33+
34+
@Override
35+
public void close() {
36+
executeAndRelease(getLibrary(), library -> library.CloseConnection(pool.getId(), getId()));
37+
}
38+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spannerlib;
18+
19+
import static com.google.cloud.spannerlib.internal.SpannerLibrary.executeAndRelease;
20+
21+
import com.google.cloud.spannerlib.internal.GoString;
22+
import com.google.cloud.spannerlib.internal.MessageHandler;
23+
import com.google.cloud.spannerlib.internal.SpannerLibrary;
24+
25+
/**
26+
* A {@link Pool} that has been created by SpannerLib. A {@link Pool} can create any number of
27+
* {@link Connection} instances. All {@link Connection} instances share the same underlying Spanner
28+
* client.
29+
*/
30+
public class Pool extends AbstractLibraryObject {
31+
32+
/** Creates a new {@link Pool} using the given connection string. */
33+
public static Pool createPool(String connectionString) {
34+
SpannerLibrary library = SpannerLibrary.getInstance();
35+
try (MessageHandler message =
36+
library.execute(lib -> lib.CreatePool(new GoString(connectionString)))) {
37+
return new Pool(library, message.getObjectId());
38+
}
39+
}
40+
41+
private Pool(SpannerLibrary library, long id) {
42+
super(library, id);
43+
}
44+
45+
@Override
46+
public void close() {
47+
executeAndRelease(getLibrary(), library -> library.ClosePool(getId()));
48+
}
49+
50+
/** Creates a new {@link Connection} in this {@link Pool}. */
51+
public Connection createConnection() {
52+
try (MessageHandler message =
53+
getLibrary().execute(library -> library.CreateConnection(getId()))) {
54+
return new Connection(this, message.getObjectId());
55+
}
56+
}
57+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spannerlib;
18+
19+
import com.google.rpc.Code;
20+
import com.google.rpc.Status;
21+
22+
public class SpannerLibException extends RuntimeException {
23+
private final Status status;
24+
25+
public SpannerLibException(Status status) {
26+
super(status.getMessage());
27+
this.status = status;
28+
}
29+
30+
public SpannerLibException(Status status, Throwable cause) {
31+
super(status.getMessage(), cause);
32+
this.status = status;
33+
}
34+
35+
public SpannerLibException(Code code, String message) {
36+
super(message);
37+
this.status = Status.newBuilder().setCode(code.getNumber()).setMessage(message).build();
38+
}
39+
40+
public SpannerLibException(Code code, String message, Throwable cause) {
41+
super(message, cause);
42+
this.status = Status.newBuilder().setCode(code.getNumber()).setMessage(message).build();
43+
}
44+
45+
public Status getStatus() {
46+
return status;
47+
}
48+
}

0 commit comments

Comments
 (0)