Skip to content

Commit 6dce35b

Browse files
committed
jdbi javadoc/checkstyle + make sqlobject request scoped only
1 parent 0c48095 commit 6dce35b

File tree

3 files changed

+185
-12
lines changed

3 files changed

+185
-12
lines changed

modules/jooby-jdbi/src/main/java/io/jooby/internal/jdbi/SqlObjectProvider.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,30 @@
55
*/
66
package io.jooby.internal.jdbi;
77

8+
import io.jooby.RequestScope;
9+
import io.jooby.jdbi.TransactionalRequest;
810
import org.jdbi.v3.core.Handle;
11+
import org.jdbi.v3.core.Jdbi;
912

1013
import javax.inject.Provider;
1114

1215
public class SqlObjectProvider implements Provider {
13-
private Provider<Handle> handle;
14-
16+
private Jdbi jdbi;
1517
private Class type;
1618

17-
public SqlObjectProvider(Provider<Handle> handle, Class type) {
18-
this.handle = handle;
19+
public SqlObjectProvider(Jdbi jdbi, Class type) {
20+
this.jdbi = jdbi;
1921
this.type = type;
2022
}
2123

2224
@Override public Object get() {
23-
Handle handle = this.handle.get();
25+
Handle handle = RequestScope.get(jdbi);
26+
if (handle == null) {
27+
// TODO: Replace with a Usage exception
28+
throw new IllegalStateException(
29+
"No handle was attached to current request. Make sure `" + TransactionalRequest.class
30+
.getName() + "` was installed it");
31+
}
2432
return handle.attach(type);
2533
}
2634
}

modules/jooby-jdbi/src/main/java/io/jooby/jdbi/JdbiModule.java

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,57 @@
2222
import java.util.List;
2323
import java.util.function.Function;
2424

25+
/**
26+
* Jdbi module: https://jooby.io/modules/hikari.
27+
*
28+
* Usage:
29+
*
30+
* - Add hikari and jdbi dependency
31+
*
32+
* - Install them
33+
*
34+
* <pre>{@code
35+
* {
36+
* install(new HikariModule());
37+
*
38+
* install(new JdbiModule());
39+
* }
40+
* }</pre>
41+
*
42+
* - Use it
43+
*
44+
* <pre>{code
45+
* {
46+
*
47+
* get("/", ctx -> {
48+
* Jdbi jdbi = require(Jdbi.class);
49+
* // do with jdbi
50+
* });
51+
*
52+
* }
53+
* }</pre>
54+
*
55+
* Handle instances are also available:
56+
*
57+
* <pre>{code
58+
* {
59+
*
60+
* get("/", ctx -> {
61+
* try(Handle handle = require(Handle.class)) {
62+
* // do with handle
63+
* }
64+
* });
65+
*
66+
* }
67+
* }</pre>
68+
*
69+
* The use of try-with-resources is required here. Handle must be closed once you finish.
70+
*
71+
* For automatic handle managment see the {@link TransactionalRequest} class.
72+
*
73+
* @author edgar
74+
* @since 2.0.0
75+
*/
2576
public class JdbiModule implements Extension {
2677

2778
private String name;
@@ -30,26 +81,78 @@ public class JdbiModule implements Extension {
3081

3182
private List<Class> sqlObjects = Collections.emptyList();
3283

84+
/**
85+
* Creates a new Jdbi module using the <code>db</code> property key. This key must be
86+
* present in the application configuration file, like:
87+
*
88+
* <pre>{@code
89+
* db.url = "jdbc:url"
90+
* db.user = dbuser
91+
* db.password = dbpass
92+
* }</pre>
93+
*/
3394
public JdbiModule() {
3495
this("db");
3596
}
3697

98+
/**
99+
* Creates a new Jdbi module. The database parameter can be one of:
100+
*
101+
* - A property key defined in your application configuration file, like <code>db</code>.
102+
* - A special h2 database: mem, local or tmp.
103+
* - A jdbc connection string, like: <code>jdbc:mysql://localhost/db</code>
104+
*
105+
* @param name Database key, database type or connection string.
106+
*/
37107
public JdbiModule(@Nonnull String name) {
38108
this.name = name;
39109
this.factory = null;
40110
}
41111

42-
public JdbiModule(Function<DataSource, Jdbi> factory) {
43-
this();
44-
this.factory = factory;
112+
/**
113+
* Creates a new Jdbi module using the given jdbi factory. The jdbi service is registered as
114+
* <code>db</code>.
115+
*
116+
* @param factory Jdbi factory.
117+
*/
118+
public JdbiModule(@Nonnull Function<DataSource, Jdbi> factory) {
119+
this("db", factory);
45120
}
46121

47-
public JdbiModule(String name, Function<DataSource, Jdbi> factory) {
122+
/**
123+
* Creates a new Jdbi module using the given jdbi factory.
124+
*
125+
* @param name Name for registering the service.
126+
* @param factory Jdbi factory.
127+
*/
128+
public JdbiModule(@Nonnull String name, @Nonnull Function<DataSource, Jdbi> factory) {
48129
this(name);
49130
this.factory = factory;
50131
}
51132

52-
public JdbiModule sqlObjects(Class... sqlObjects) {
133+
/**
134+
* Attach SQL objects to a jdbi handle.
135+
*
136+
* This method simplify the injection or require of SQL objects. So, it is just a
137+
* shortcut for {@link Handle#attach(Class)}. Due the SQL objects depends on a Handle this
138+
* method is only available when the {@link TransactionalRequest} decorator is present.
139+
*
140+
* <pre>{@code
141+
* install(new JdbiModule()
142+
* .sqlObjects(UserDAO.class)
143+
* );
144+
*
145+
* decorator(new TransactionalRequest());
146+
*
147+
* get("/users", ctx -> {
148+
* UserDAO dao = require(UserDAO.class);
149+
* });
150+
* }</pre>
151+
*
152+
* @param sqlObjects List of SQL object to register as services.
153+
* @return This module.
154+
*/
155+
public @Nonnull JdbiModule sqlObjects(@Nonnull Class... sqlObjects) {
53156
this.sqlObjects = Arrays.asList(sqlObjects);
54157
return this;
55158
}
@@ -73,7 +176,7 @@ public JdbiModule sqlObjects(Class... sqlObjects) {
73176

74177
/** SQLObjects: */
75178
for (Class<?> sqlObject : sqlObjects) {
76-
registry.put(sqlObject, new SqlObjectProvider(provider, sqlObject));
179+
registry.put(sqlObject, new SqlObjectProvider(jdbi, sqlObject));
77180
}
78181
}
79182

modules/jooby-jdbi/src/main/java/io/jooby/jdbi/TransactionalRequest.java

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,84 @@
1414

1515
import javax.annotation.Nonnull;
1616

17+
/**
18+
* Attach {@link Handle} to the current request. The route pipeline runs inside a transaction
19+
* which is commit on success or rollback in case of exception.
20+
*
21+
* Once route pipeline is executed the handle is detached from current request and closed it.
22+
*
23+
* Usage:
24+
*
25+
* <pre>{@code
26+
* {
27+
*
28+
* install(new HikariModule());
29+
*
30+
* install(new JdbiModule());
31+
*
32+
* decorator(new TransactionalRequest());
33+
*
34+
* get("/handle", ctx -> {
35+
* Handle handle = require(Handle.class);
36+
* // work with handle.
37+
* });
38+
* }
39+
* }</pre>
40+
*
41+
* The {@link Handle} should NOT be closed it by application code.
42+
*
43+
* SQL Objects example:
44+
*
45+
* <pre>{@code
46+
* {
47+
*
48+
* install(new HikariModule());
49+
*
50+
* install(new JdbiModule()
51+
* .sqlObjects(UserDAO.class)
52+
* );
53+
*
54+
* decorator(new TransactionalRequest());
55+
*
56+
* get("/handle", ctx -> {
57+
* UserDAO dao = require(UserDAO.class);
58+
* // work with user dao
59+
* });
60+
* }
61+
* }</pre>
62+
*
63+
* The <code>UserDAO</code> sql object is attached to the current/request attached {@link Handle}.
64+
*
65+
* @author edgar
66+
* @since 2.0.0
67+
*/
1768
public class TransactionalRequest implements Decorator {
1869

1970
private ServiceKey<Jdbi> key;
2071

72+
/**
73+
* Creates a transactional request. A jdbi with the given name must be available in the service
74+
* registry.
75+
*
76+
* This constructor should be used only if you have multiple Jdbi installations.
77+
*
78+
* @param name Jdbi service name.
79+
*/
2180
public TransactionalRequest(@Nonnull String name) {
2281
key = ServiceKey.key(Jdbi.class, name);
2382
}
2483

84+
/**
85+
* Creates a transactional request.
86+
*/
2587
public TransactionalRequest() {
2688
key = ServiceKey.key(Jdbi.class);
2789
}
2890

2991
@Nonnull @Override public Route.Handler apply(@Nonnull Route.Handler next) {
3092
return ctx -> {
3193
Jdbi jdbi = ctx.require(key);
32-
try(Handle handle = jdbi.open()) {
94+
try (Handle handle = jdbi.open()) {
3395
RequestScope.bind(jdbi, handle);
3496
return handle.inTransaction(h -> next.apply(ctx));
3597
} finally {

0 commit comments

Comments
 (0)