Skip to content

Commit ff01cad

Browse files
committed
MappingProvider & pooled proxies
1 parent 99c396c commit ff01cad

8 files changed

Lines changed: 176 additions & 192 deletions

File tree

asql-api/src/main/java/me/zort/sqllib/api/mapping/StatementMappingFactory.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import me.zort.sqllib.api.SQLConnection;
44

5+
import java.util.function.Supplier;
6+
57
/**
68
* The StatementMappingFactory is responsible for creating new {@link StatementMappingStrategy}
79
* for defined interfaces.
@@ -15,11 +17,14 @@ public interface StatementMappingFactory {
1517
* is responsible for handling that specific interface.
1618
*
1719
* @param interfaceClass The interface class
18-
* @param connection The connection to use.
20+
* @param connectionFactory The connection factory to use.
1921
* @param <T> The interface class type.
2022
* @return The StatementMapping.
2123
*/
22-
<T> StatementMappingStrategy<T> strategy(Class<T> interfaceClass, SQLConnection connection);
24+
<T> StatementMappingStrategy<T> strategy(
25+
Class<T> interfaceClass,
26+
Supplier<SQLConnection> connectionFactory
27+
);
2328

2429
StatementMappingResultAdapter resultAdapter();
2530

asql-core/src/main/java/me/zort/sqllib/SQLDatabaseConnection.java

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import me.zort.sqllib.api.data.Row;
1111
import me.zort.sqllib.api.mapping.StatementMappingFactory;
1212
import me.zort.sqllib.api.mapping.StatementMappingOptions;
13-
import me.zort.sqllib.api.mapping.StatementMappingRegistry;
1413
import me.zort.sqllib.api.model.SchemaSynchronizer;
1514
import me.zort.sqllib.api.model.TableSchema;
1615
import me.zort.sqllib.api.model.TableSchemaBuilder;
@@ -19,6 +18,7 @@
1918
import me.zort.sqllib.internal.impl.QueryResultImpl;
2019
import me.zort.sqllib.internal.query.*;
2120
import me.zort.sqllib.internal.query.part.SetStatement;
21+
import me.zort.sqllib.mapping.MappingProvider;
2222
import me.zort.sqllib.transaction.Transaction;
2323
import org.jetbrains.annotations.ApiStatus;
2424
import org.jetbrains.annotations.NotNull;
@@ -42,7 +42,8 @@
4242
* @author ZorTik
4343
*/
4444
@SuppressWarnings("unused")
45-
public abstract class SQLDatabaseConnection implements SQLConnection, Closeable {
45+
public abstract class SQLDatabaseConnection
46+
extends MappingProvider implements SQLConnection, Closeable {
4647

4748
private final SQLConnectionFactory connectionFactory;
4849
private final transient List<SQLDatabaseConnectionImpl.CodeObserver> codeHandlers;
@@ -54,20 +55,15 @@ public abstract class SQLDatabaseConnection implements SQLConnection, Closeable
5455
private int errorCount = 0;
5556

5657
public SQLDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory) {
58+
super();
5759
this.connectionFactory = connectionFactory;
5860
this.connection = null;
5961
this.codeHandlers = new CopyOnWriteArrayList<>();
6062

63+
setMConnectionFactory(() -> this);
6164
registerConnection(this);
6265
}
6366

64-
/**
65-
* Sets a mapping to use when using {@link SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)}.
66-
*
67-
* @param mappingFactory Mapping factory to use.
68-
*/
69-
public abstract void setProxyMapping(final @NotNull StatementMappingFactory mappingFactory);
70-
7167
/**
7268
* Sets the schema synchronizer to use with synchronizeModel methods.
7369
*
@@ -76,50 +72,6 @@ public SQLDatabaseConnection(final @NotNull SQLConnectionFactory connectionFacto
7672
@ApiStatus.Experimental
7773
public abstract void setSchemaSynchronizer(SchemaSynchronizer<SQLDatabaseConnection> synchronizer);
7874

79-
@ApiStatus.Experimental
80-
public abstract StatementMappingRegistry getMappingRegistry();
81-
82-
/**
83-
* @deprecated Use {@link SQLDatabaseConnection#createProxy(Class)} instead.
84-
*/
85-
@Deprecated
86-
public abstract <T> T createGate(Class<T> mappingInterface);
87-
88-
/**
89-
* Constructs a mapping repository based on provided interface.
90-
* The interface should follow rules for creating mapping repositories
91-
* in this library.
92-
* <p>
93-
* Example:
94-
* <pre>
95-
* &#64;Table("users")
96-
* public interface MyRepository {
97-
* &#64;Select("*")
98-
* &#64;Where(&#64;Where.Condition(column = "firstname", value = "{First Name}"))
99-
* &#64;Limit(1)
100-
* Optional&lt;User&gt; getUser(&#64;Placeholder("First Name") String firstName);
101-
*
102-
* &#64;Select
103-
* List&lt;User&gt; getUsers();
104-
*
105-
* &#64;Delete
106-
* QueryResult deleteUsers();
107-
* }
108-
*
109-
* SQLDatabaseConnection connection = ...;
110-
* MyRepository repository = connection.createGate(MyRepository.class);
111-
*
112-
* Optional&lt;User&gt; user = repository.getUser("John");
113-
* </pre>
114-
*
115-
* @param mappingInterface Interface to create mapping repository for.
116-
* @param <T> Type of mapping repository.
117-
* @return Mapping repository.
118-
*/
119-
public abstract <T> T createProxy(Class<T> mappingInterface);
120-
121-
public abstract <T> T createProxy(Class<T> mappingInterface, @NotNull StatementMappingOptions options);
122-
12375
public abstract boolean buildEntitySchema(String tableName, Class<?> entityClass);
12476

12577
/**

asql-core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java

Lines changed: 2 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
import me.zort.sqllib.api.data.QueryResult;
1414
import me.zort.sqllib.api.data.QueryRowsResult;
1515
import me.zort.sqllib.api.data.Row;
16-
import me.zort.sqllib.api.mapping.MappingProxyInstance;
17-
import me.zort.sqllib.api.mapping.StatementMappingFactory;
18-
import me.zort.sqllib.api.mapping.StatementMappingOptions;
19-
import me.zort.sqllib.api.mapping.StatementMappingRegistry;
2016
import me.zort.sqllib.api.model.SchemaSynchronizer;
2117
import me.zort.sqllib.api.model.TableSchema;
2218
import me.zort.sqllib.api.model.TableSchemaBuilder;
@@ -28,12 +24,9 @@
2824
import me.zort.sqllib.internal.fieldResolver.LinkedOneFieldResolver;
2925
import me.zort.sqllib.internal.impl.DefaultObjectMapper;
3026
import me.zort.sqllib.internal.impl.QueryResultImpl;
31-
import me.zort.sqllib.mapping.DefaultStatementMappingFactory;
32-
import me.zort.sqllib.mapping.MappingRegistryImpl;
33-
import me.zort.sqllib.mapping.ProxyInstanceImpl;
27+
import me.zort.sqllib.model.SQLSchemaSynchronizer;
3428
import me.zort.sqllib.model.builder.DatabaseSchemaBuilder;
3529
import me.zort.sqllib.model.builder.EntitySchemaBuilder;
36-
import me.zort.sqllib.model.SQLSchemaSynchronizer;
3730
import me.zort.sqllib.pool.PooledSQLDatabaseConnection;
3831
import me.zort.sqllib.transaction.Transaction;
3932
import me.zort.sqllib.util.Validator;
@@ -43,7 +36,6 @@
4336

4437
import java.lang.reflect.Field;
4538
import java.lang.reflect.Modifier;
46-
import java.lang.reflect.Proxy;
4739
import java.sql.*;
4840
import java.util.HashMap;
4941
import java.util.Map;
@@ -80,8 +72,6 @@ static SQLDatabaseOptions defaultOptions() {
8072

8173
@Getter
8274
private final ISQLDatabaseOptions options;
83-
private final transient StatementMappingRegistry mappingRegistry;
84-
private transient StatementMappingFactory mappingFactory;
8575
private transient ObjectMapper objectMapper;
8676
private transient CacheManager cacheManager;
8777
@Setter
@@ -110,10 +100,8 @@ public SQLDatabaseConnectionImpl(final @NotNull SQLConnectionFactory connectionF
110100
super(connectionFactory);
111101
this.options = options == null ? defaultOptions() : options;
112102
this.objectMapper = new DefaultObjectMapper(this);
113-
this.mappingFactory = new DefaultStatementMappingFactory();
114103
this.transaction = null;
115104
this.logger = Logger.getGlobal();
116-
this.mappingRegistry = new MappingRegistryImpl(this);
117105

118106
setSchemaSynchronizer(new SQLSchemaSynchronizer());
119107
enableCaching(CacheManager.noCache());
@@ -146,15 +134,6 @@ public void setObjectMapper(final @NotNull ObjectMapper objectMapper) {
146134
this.objectMapper = Objects.requireNonNull(objectMapper, "Object mapper cannot be null!");
147135
}
148136

149-
/**
150-
* Sets a mapping to use when using {@link SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)}.
151-
*
152-
* @param mappingFactory Mapping factory to use.
153-
*/
154-
public void setProxyMapping(final @NotNull StatementMappingFactory mappingFactory) {
155-
this.mappingFactory = Objects.requireNonNull(mappingFactory, "Mapping factory cannot be null!");
156-
}
157-
158137
/**
159138
* Enabled caching for this connection.
160139
*
@@ -176,7 +155,7 @@ public void enableCaching(CacheManager cacheManager) {
176155
@ApiStatus.Experimental
177156
@Override
178157
public boolean synchronizeModel() {
179-
return mappingRegistry.getProxyInstances()
158+
return getMappingRegistry().getProxyInstances()
180159
.stream().flatMap(i -> i.getTableSchemas(
181160
getOptions().getNamingStrategy(),
182161
this instanceof SQLiteDatabaseConnection).stream())
@@ -235,86 +214,6 @@ public SchemaSynchronizer<SQLDatabaseConnection> getSchemaSynchronizer() {
235214
return schemaSynchronizer;
236215
}
237216

238-
@ApiStatus.Experimental
239-
@Override
240-
public StatementMappingRegistry getMappingRegistry() {
241-
return mappingRegistry;
242-
}
243-
244-
/**
245-
* Constructs a mapping proxy based on provided interface.
246-
* The interface should follow rules for creating mapping repositories
247-
* in this library.
248-
*
249-
* @param mappingInterface Interface to create mapping repository for.
250-
* @param <T> Type of mapping repository.
251-
* @return Mapping repository.
252-
* @see SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)
253-
*/
254-
public <T> T createProxy(Class<T> mappingInterface) {
255-
return createProxy(mappingInterface, new StatementMappingOptions.Builder().build());
256-
}
257-
258-
/**
259-
* Replaced with {@link SQLDatabaseConnection#createProxy(Class)}.
260-
*
261-
* @deprecated Will be removed in future releases.
262-
*/
263-
@Deprecated
264-
@Override
265-
public <T> T createGate(Class<T> mappingInterface) {
266-
return createProxy(mappingInterface);
267-
}
268-
269-
/**
270-
* Constructs a mapping repository based on provided interface.
271-
* The interface should follow rules for creating mapping repositories
272-
* in this library.
273-
* <p>
274-
* Example:
275-
* <pre>
276-
* &#64;Table("users")
277-
* public interface MyRepository {
278-
* &#64;Select("*")
279-
* &#64;Where(&#64;Where.Condition(column = "firstname", value = "{First Name}"))
280-
* &#64;Limit(1)
281-
* Optional&lt;User&gt; getUser(&#64;Placeholder("First Name") String firstName);
282-
*
283-
* &#64;Select
284-
* List&lt;User&gt; getUsers();
285-
*
286-
* &#64;Delete
287-
* QueryResult deleteUsers();
288-
* }
289-
*
290-
* SQLDatabaseConnection connection = ...;
291-
* MyRepository repository = connection.createGate(MyRepository.class);
292-
*
293-
* Optional&lt;User&gt; user = repository.getUser("John");
294-
* </pre>
295-
*
296-
* @param mappingInterface Interface to create mapping repository for.
297-
* @param <T> Type of mapping repository.
298-
* @return Mapping repository.
299-
*/
300-
@SuppressWarnings("unchecked")
301-
public final <T> T createProxy(final @NotNull Class<T> mappingInterface, final @NotNull StatementMappingOptions options) {
302-
Objects.requireNonNull(mappingInterface, "Mapping interface cannot be null!");
303-
Objects.requireNonNull(options, "Options cannot be null!");
304-
305-
AtomicReference<MappingProxyInstance<T>> instanceReference = new AtomicReference<>();
306-
T rawInstance = (T) Proxy.newProxyInstance(mappingInterface.getClassLoader(),
307-
new Class[]{mappingInterface}, (proxy, method, args) -> instanceReference.get().invoke(proxy, method, args));
308-
instanceReference.set(new ProxyInstanceImpl<>(mappingInterface,
309-
options,
310-
mappingFactory.strategy(mappingInterface, this),
311-
mappingFactory.resultAdapter()));
312-
313-
MappingProxyInstance<T> proxyInstanceWrapper = instanceReference.get();
314-
mappingRegistry.registerProxy(proxyInstanceWrapper);
315-
return rawInstance;
316-
}
317-
318217
@ApiStatus.Experimental
319218
public final boolean buildEntitySchema(final @NotNull String tableName, final @NotNull Class<?> entityClass) {
320219
Objects.requireNonNull(entityClass, "Entity class cannot be null!");

asql-core/src/main/java/me/zort/sqllib/mapping/DefaultStatementMapping.java

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import me.zort.sqllib.api.data.QueryRowsResult;
77
import me.zort.sqllib.api.mapping.StatementMappingOptions;
88
import me.zort.sqllib.api.mapping.StatementMappingStrategy;
9+
import me.zort.sqllib.internal.factory.SQLConnectionFactory;
910
import me.zort.sqllib.internal.query.QueryNode;
1011
import me.zort.sqllib.internal.query.ResultSetAware;
1112
import me.zort.sqllib.mapping.annotation.Append;
@@ -16,6 +17,7 @@
1617
import java.lang.annotation.Annotation;
1718
import java.lang.reflect.Method;
1819
import java.lang.reflect.Parameter;
20+
import java.util.function.Supplier;
1921

2022
/**
2123
* This mapping strategy uses annotations from me.zort.sqllib.mapping.annotation
@@ -26,10 +28,10 @@
2628
*/
2729
public class DefaultStatementMapping<T> implements StatementMappingStrategy<T> {
2830

29-
private final SQLConnection connection;
31+
private final Supplier<SQLConnection> connectionFactory;
3032

31-
public DefaultStatementMapping(SQLConnection connection) {
32-
this.connection = connection;
33+
public DefaultStatementMapping(Supplier<SQLConnection> connectionFactory) {
34+
this.connectionFactory = connectionFactory;
3335
}
3436

3537
@SuppressWarnings("unchecked")
@@ -42,33 +44,43 @@ public QueryResult executeQuery(StatementMappingOptions options, Method method,
4244
i++;
4345
}
4446

45-
Annotation queryAnnotation = filterQueryAnnotation(method, args);
46-
QueryAnnotation wrappedAnnotation = QueryAnnotation.wrap(queryAnnotation);
47+
SQLConnection connection = connectionFactory.get();
4748

48-
if (wrappedAnnotation == null) {
49-
throw new SQLMappingException("No query builder found for method " + method.getName() + "! Is query annotation present?", method, args);
50-
} else if (!(connection instanceof SQLDatabaseConnection)) {
51-
throw new SQLMappingException("Connection is not a SQLDatabaseConnection!", method, args);
52-
}
49+
try {
50+
Annotation queryAnnotation = filterQueryAnnotation(method, args);
51+
QueryAnnotation wrappedAnnotation = QueryAnnotation.wrap(queryAnnotation);
5352

54-
QueryNode<?> node = wrappedAnnotation.getQueryBuilder().build(
55-
new QueryAnnotation.DefaultMappingDetails(connection, options), queryAnnotation,
56-
method, parameters);
57-
if (method.isAnnotationPresent(Append.class)) {
58-
Append append = method.getAnnotation(Append.class);
59-
node.then(new PlaceholderMapper(parameters).assignValues(append.value()));
60-
}
53+
if (wrappedAnnotation == null) {
54+
throw new SQLMappingException("No query builder found for method " + method.getName() + "! Is query annotation present?", method, args);
55+
} else if (!(connection instanceof SQLDatabaseConnection)) {
56+
throw new SQLMappingException("Connection is not a SQLDatabaseConnection!", method, args);
57+
}
6158

62-
if (mapTo != null && wrappedAnnotation.isProducesResult() && QueryRowsResult.class.isAssignableFrom(mapTo)) {
63-
return ((SQLDatabaseConnection) connection).query(node);
64-
}
59+
QueryNode<?> node = wrappedAnnotation.getQueryBuilder().build(
60+
new QueryAnnotation.DefaultMappingDetails(connection, options), queryAnnotation,
61+
method, parameters);
62+
if (method.isAnnotationPresent(Append.class)) {
63+
Append append = method.getAnnotation(Append.class);
64+
node.then(new PlaceholderMapper(parameters).assignValues(append.value()));
65+
}
6566

66-
if (wrappedAnnotation.isProducesResult() && node instanceof ResultSetAware) {
67-
return mapTo != null
68-
? ((SQLDatabaseConnection) connection).query(node, mapTo)
69-
: ((SQLDatabaseConnection) connection).query(node);
70-
} else {
71-
return ((SQLDatabaseConnection) connection).exec(node);
67+
if (mapTo != null && wrappedAnnotation.isProducesResult() && QueryRowsResult.class.isAssignableFrom(mapTo)) {
68+
return ((SQLDatabaseConnection) connection).query(node);
69+
}
70+
71+
if (wrappedAnnotation.isProducesResult() && node instanceof ResultSetAware) {
72+
return mapTo != null
73+
? ((SQLDatabaseConnection) connection).query(node, mapTo)
74+
: ((SQLDatabaseConnection) connection).query(node);
75+
} else {
76+
return ((SQLDatabaseConnection) connection).exec(node);
77+
}
78+
} finally {
79+
if (connection instanceof SQLDatabaseConnection) {
80+
((SQLDatabaseConnection) connection).close();
81+
} else {
82+
connection.disconnect();
83+
}
7284
}
7385
}
7486

0 commit comments

Comments
 (0)