|
1 | 1 | package me.zort.sqllib; |
2 | 2 |
|
3 | 3 | import com.google.gson.Gson; |
4 | | -import lombok.AllArgsConstructor; |
5 | | -import lombok.Data; |
6 | | -import lombok.Getter; |
7 | | -import lombok.RequiredArgsConstructor; |
| 4 | +import lombok.*; |
8 | 5 | import me.zort.sqllib.api.Query; |
9 | 6 | import me.zort.sqllib.api.StatementFactory; |
10 | 7 | import me.zort.sqllib.api.data.QueryResult; |
|
14 | 11 | import me.zort.sqllib.internal.Defaults; |
15 | 12 | import me.zort.sqllib.internal.annotation.JsonField; |
16 | 13 | import me.zort.sqllib.internal.factory.SQLConnectionFactory; |
| 14 | +import me.zort.sqllib.internal.fieldResolver.ConstructorParameterResolver; |
17 | 15 | import me.zort.sqllib.internal.fieldResolver.LinkedOneFieldResolver; |
18 | 16 | import me.zort.sqllib.internal.impl.DefaultNamingStrategy; |
19 | 17 | import me.zort.sqllib.internal.impl.QueryResultImpl; |
@@ -45,9 +43,7 @@ public class SQLDatabaseConnectionImpl extends SQLDatabaseConnection { |
45 | 43 |
|
46 | 44 | @Getter |
47 | 45 | private final SQLDatabaseOptions options; |
48 | | - // Resolvers used after no value is found for the field |
49 | | - // in mapped object as backup. |
50 | | - private final List<FieldValueResolver> backupValueResolvers; |
| 46 | + private final ObjectMapper objectMapper; |
51 | 47 |
|
52 | 48 | /** |
53 | 49 | * Constructs new instance of this implementation with default |
@@ -78,16 +74,17 @@ public SQLDatabaseConnectionImpl(SQLConnectionFactory connectionFactory, @Nullab |
78 | 74 | ); |
79 | 75 |
|
80 | 76 | this.options = options; |
81 | | - this.backupValueResolvers = Collections.synchronizedList(new ArrayList<>()); |
| 77 | + this.objectMapper = new ObjectMapper(this); |
82 | 78 |
|
83 | 79 | // Default backup value resolvers. |
84 | 80 | registerBackupValueResolver(new LinkedOneFieldResolver()); |
| 81 | + registerBackupValueResolver(new ConstructorParameterResolver()); |
85 | 82 | } |
86 | 83 |
|
87 | | - public void registerBackupValueResolver(@NotNull FieldValueResolver resolver) { |
| 84 | + public void registerBackupValueResolver(@NotNull ObjectMapper.FieldValueResolver resolver) { |
88 | 85 | Objects.requireNonNull(resolver, "Resolver cannot be null!"); |
89 | 86 |
|
90 | | - backupValueResolvers.add(resolver); |
| 87 | + objectMapper.getBackupValueResolvers().add(resolver); |
91 | 88 | } |
92 | 89 |
|
93 | 90 | /** |
@@ -162,7 +159,7 @@ public <T> QueryRowsResult<T> query(Query query, Class<T> typeClass) { |
162 | 159 | QueryRowsResult<Row> resultRows = query(query.getAncestor()); |
163 | 160 | QueryRowsResult<T> result = new QueryRowsResult<>(resultRows.isSuccessful()); |
164 | 161 | for(Row row : resultRows) { |
165 | | - Optional.ofNullable(assignValues(row, typeClass)) |
| 162 | + Optional.ofNullable(objectMapper.assignValues(row, typeClass)) |
166 | 163 | .ifPresent(result::add); |
167 | 164 | } |
168 | 165 | return result; |
@@ -219,95 +216,6 @@ public QueryResult exec(Query query) { |
219 | 216 | } |
220 | 217 | } |
221 | 218 |
|
222 | | - @Nullable |
223 | | - private <T> T assignValues(Row row, Class<T> typeClass) { |
224 | | - T instance = null; |
225 | | - try { |
226 | | - try { |
227 | | - Constructor<T> c = typeClass.getConstructor(); |
228 | | - c.setAccessible(true); |
229 | | - instance = c.newInstance(); |
230 | | - } catch (NoSuchMethodException e) { |
231 | | - for(Constructor<?> c : typeClass.getConstructors()) { |
232 | | - if(c.getParameterCount() == row.size()) { |
233 | | - Parameter[] params = c.getParameters(); |
234 | | - Object[] vals = new Object[c.getParameterCount()]; |
235 | | - for(int i = 0; i < row.size(); i++) { |
236 | | - Parameter param = params[i]; |
237 | | - vals[i] = buildElementValue(param, row); |
238 | | - } |
239 | | - try { |
240 | | - instance = (T) c.newInstance(vals); |
241 | | - } catch(Exception ignored) { |
242 | | - continue; |
243 | | - } |
244 | | - } |
245 | | - } |
246 | | - } |
247 | | - for(Field field : typeClass.getDeclaredFields()) { |
248 | | - |
249 | | - if(Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) { |
250 | | - continue; |
251 | | - } |
252 | | - |
253 | | - try { |
254 | | - field.setAccessible(true); |
255 | | - field.set(instance, buildElementValue(field, row)); |
256 | | - } catch(SecurityException ignored) { |
257 | | - debug(String.format("Field %s on class %s cannot be set accessible!", |
258 | | - field.getName(), |
259 | | - typeClass.getName())); |
260 | | - } catch(Exception ignored) { |
261 | | - continue; |
262 | | - } |
263 | | - } |
264 | | - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { |
265 | | - debug("Cannot instantinate " + typeClass.getName() + " for assigning attributes from row!"); |
266 | | - e.printStackTrace(); |
267 | | - return null; |
268 | | - } |
269 | | - return instance; |
270 | | - } |
271 | | - |
272 | | - @Nullable |
273 | | - private Object buildElementValue(AnnotatedElement element, Row row) { |
274 | | - String name; |
275 | | - Type type; |
276 | | - if(element instanceof Field) { |
277 | | - name = ((Field) element).getName(); |
278 | | - type = ((Field) element).getGenericType(); |
279 | | - } else if(element instanceof Parameter) { // TODO: Parameter names are arg[a-zA-Z0-9]+, use different strategy. |
280 | | - name = ((Parameter) element).getName(); |
281 | | - type = ((Parameter) element).getType(); |
282 | | - } else { |
283 | | - return null; |
284 | | - } |
285 | | - Object obj = row.get(name); |
286 | | - if(obj == null) { |
287 | | - String converted; |
288 | | - if((obj = row.get(converted = options.getNamingStrategy().fieldNameToColumn(name))) == null) { |
289 | | - |
290 | | - // Now backup resolvers come. |
291 | | - for(FieldValueResolver resolver : backupValueResolvers) { |
292 | | - Object backupValue = resolver.obtainValue(this, element, row, name, converted, type); |
293 | | - if(backupValue != null) { |
294 | | - return backupValue; |
295 | | - } |
296 | | - } |
297 | | - |
298 | | - debug(String.format("Cannot find column for target %s (%s)", name, converted)); |
299 | | - return null; |
300 | | - } |
301 | | - } |
302 | | - if(element.isAnnotationPresent(JsonField.class) && obj instanceof String) { |
303 | | - String jsonString = (String) obj; |
304 | | - Gson gson = options.getGson(); |
305 | | - return gson.fromJson(jsonString, type); |
306 | | - } else { |
307 | | - return obj; |
308 | | - } |
309 | | - } |
310 | | - |
311 | 219 | private boolean handleAutoReconnect() { |
312 | 220 | if(options.isAutoReconnect() && !isConnected()) { |
313 | 221 | debug("Trying to make a new connection with the database!"); |
@@ -390,15 +298,6 @@ public PreparedStatement prepare(Connection connection) throws SQLException { |
390 | 298 | } |
391 | 299 | } |
392 | 300 |
|
393 | | - public interface FieldValueResolver { |
394 | | - Object obtainValue(SQLDatabaseConnectionImpl connection, |
395 | | - AnnotatedElement element, |
396 | | - Row row, |
397 | | - String fieldName, |
398 | | - String convertedName, |
399 | | - Type type); |
400 | | - } |
401 | | - |
402 | 301 | @AllArgsConstructor |
403 | 302 | @Data |
404 | 303 | public static class UnknownValueWrapper { |
|
0 commit comments