diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml
index fd2bdcee..645984da 100644
--- a/.github/workflows/pipeline.yml
+++ b/.github/workflows/pipeline.yml
@@ -45,16 +45,6 @@ jobs:
run: java -version
- name: Test with Maven java 17
run: mvn test
- - name: Setup JDK 11 for testing
- uses: actions/setup-java@v4
- with:
- java-version: '11'
- distribution: 'temurin'
- cache: maven
- - name: Print java version
- run: java -version
- - name: Test with Maven java 11
- run: mvn test
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- name: Update dependency graph
diff --git a/core/pom.xml b/core/pom.xml
index 36cfec76..06e87169 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -13,7 +13,7 @@
org.sql2o
sql2o-parent
- 1.8.0-SNAPSHOT
+ 1.9.0-SNAPSHOT
sql2o
jar
@@ -66,7 +66,7 @@
org.junit.jupiter
junit-jupiter
- 5.10.2
+ 5.11.0
test
@@ -94,8 +94,8 @@
org.apache.maven.plugins
maven-compiler-plugin
- 11
- 11
+ 17
+ 17
diff --git a/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactory.java b/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactory.java
index 4097c040..c3a909bd 100644
--- a/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactory.java
+++ b/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactory.java
@@ -1,186 +1,38 @@
package org.sql2o;
-import org.sql2o.converters.Converter;
-import org.sql2o.converters.ConverterException;
import org.sql2o.quirks.Quirks;
-import org.sql2o.reflection.Pojo;
-import org.sql2o.reflection.PojoMetadata;
-import org.sql2o.reflection.Setter;
-import org.sql2o.tools.AbstractCache;
-
-import java.sql.ResultSet;
+import org.sql2o.reflection2.ObjectBuildableFactoryDelegate;
import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-
public class DefaultResultSetHandlerFactory implements ResultSetHandlerFactory {
- private final PojoMetadata metadata;
private final Quirks quirks;
+ private final ObjectBuildableFactoryDelegate objectBuilderDelegate;
- public DefaultResultSetHandlerFactory(PojoMetadata pojoMetadata, Quirks quirks) {
- this.metadata = pojoMetadata;
+ public DefaultResultSetHandlerFactory(ObjectBuildableFactoryDelegate objectBuilderDelegate, Quirks quirks) {
+ this.objectBuilderDelegate = objectBuilderDelegate;
this.quirks = quirks;
}
- @SuppressWarnings("unchecked")
- private static Setter getSetter(
- final Quirks quirks,
- final String propertyPath,
- final PojoMetadata metadata) {
- int index = propertyPath.indexOf('.');
- if (index <= 0) {
- // Simple path - fast way
- final Setter setter = metadata.getPropertySetterIfExists(propertyPath);
- // behavior change: do not throw if POJO contains less properties
- if (setter == null) return null;
- final Converter converter = quirks.converterOf(setter.getType());
- // setter without converter
- if (converter == null) return setter;
- return new Setter() {
- public void setProperty(Object obj, Object value) {
- try {
- setter.setProperty(obj, converter.convert(value));
- } catch (ConverterException e) {
- throw new Sql2oException("Error trying to convert column " + propertyPath + " to type " + setter.getType(), e);
- }
- }
-
- public Class getType() {
- return setter.getType();
- }
- };
- }
- // dot path - long way
- // i'm too lazy now to rewrite this case so I just call old unoptimized code...
- // TODO: rewrite, get rid of POJO class
- return new Setter() {
- public void setProperty(Object obj, Object value) {
- Pojo pojo = new Pojo(metadata, metadata.isCaseSensitive(), obj);
- pojo.setProperty(propertyPath, value, quirks);
- }
-
- public Class getType() {
- // doesn't used anyway
- return Object.class;
- }
- };
- }
-
- private static class Key {
- final String stringKey;
- final DefaultResultSetHandlerFactory f;
-
- DefaultResultSetHandlerFactory factory(){
- return f;
- }
-
- private PojoMetadata getMetadata() {
- return f.metadata;
- }
-
- private Quirks getQuirksMode() {
- return f.quirks;
- }
-
- private Key(String stringKey, DefaultResultSetHandlerFactory f) {
- this.stringKey = stringKey;
- this.f = f;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Key key = (Key) o;
-
- return f.metadata.equals(key.getMetadata())
- && f.quirks == key.getQuirksMode()
- && stringKey.equals(key.stringKey);
-
- }
-
- @Override
- public int hashCode() {
- int result = f.metadata.hashCode();
- result = 31 * result + f.quirks.hashCode();
- result = 31 * result + stringKey.hashCode();
- return result;
- }
- }
-
-
- private static final AbstractCache
- c = new AbstractCache() {
- @Override
- protected ResultSetHandler evaluate(Key key, ResultSetMetaData param) {
- try {
- return key.factory().newResultSetHandler0(param);
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
- };
@SuppressWarnings("unchecked")
- public ResultSetHandler newResultSetHandler(final ResultSetMetaData meta) throws SQLException {
- StringBuilder stringBuilder = new StringBuilder();
- for (int i = 1; i <= meta.getColumnCount(); i++) {
- stringBuilder.append(quirks.getColumnName(meta,i)).append("\n");
- }
- return c.get(new Key(stringBuilder.toString(), this),meta);
+ public ResultSetHandler newResultSetHandler(final ResultSetMetaData meta) {
+ return resultSet -> {
- }
+ final var objectBuilder = objectBuilderDelegate.newObjectBuilder();
-
- @SuppressWarnings("unchecked")
- private ResultSetHandler newResultSetHandler0(final ResultSetMetaData meta) throws SQLException {
- final Setter[] setters;
- final Converter converter;
- final boolean useExecuteScalar;
- //TODO: it's possible to cache converter/setters/getters
- // cache key is ResultSetMetadata + Bean type
-
- converter = quirks.converterOf(metadata.getType());
- final int columnCount = meta.getColumnCount();
-
- setters = new Setter[columnCount + 1]; // setters[0] is always null
- for (int i = 1; i <= columnCount; i++) {
- String colName = quirks.getColumnName(meta, i);
-
- setters[i] = getSetter(quirks, colName, metadata);
-
- // If more than 1 column is fetched (we cannot fall back to executeScalar),
- // and the setter doesn't exist, throw exception.
- if (this.metadata.throwOnMappingFailure && setters[i] == null && columnCount > 1) {
- throw new Sql2oException("Could not map " + colName + " to any property.");
- }
- }
- /**
- * Fallback to executeScalar if converter exists,
- * we're selecting 1 column, and no property setter exists for the column.
- */
- useExecuteScalar = converter != null && columnCount == 1 && setters[1] == null;
- return new ResultSetHandler() {
- @SuppressWarnings("unchecked")
- public T handle(ResultSet resultSet) throws SQLException {
- if (useExecuteScalar) {
- try {
- return (T) converter.convert(quirks.getRSVal(resultSet, 1));
- } catch (ConverterException e) {
- throw new Sql2oException("Error occurred while converting value from database to type " + metadata.getType(), e);
- }
+ for (int i = 1; i <= meta.getColumnCount(); i++) {
+ final var colName = quirks.getColumnName(meta, i);
+ try {
+ objectBuilder.withValue(colName, resultSet.getObject(i));
+ } catch (ReflectiveOperationException e) {
+ throw new Sql2oException("Error when trying to set value for column [" + colName + "]", e);
}
- // otherwise we want executeAndFetch with object mapping
- Object pojo = metadata.getObjectConstructor().newInstance();
- for (int colIdx = 1; colIdx <= columnCount; colIdx++) {
- Setter setter = setters[colIdx];
- if (setter == null) continue;
- setter.setProperty(pojo, quirks.getRSVal(resultSet, colIdx));
- }
-
- return (T) pojo;
+ }
+ try {
+ return objectBuilder.build();
+ } catch (ReflectiveOperationException e) {
+ throw new Sql2oException("Error occurred while creating object from ResultSet", e);
}
};
}
diff --git a/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactoryBuilder.java b/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactoryBuilder.java
index 5f97fd9e..ac9fc602 100644
--- a/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactoryBuilder.java
+++ b/core/src/main/java/org/sql2o/DefaultResultSetHandlerFactoryBuilder.java
@@ -1,7 +1,7 @@
package org.sql2o;
import org.sql2o.quirks.Quirks;
-import org.sql2o.reflection.PojoMetadata;
+import org.sql2o.reflection2.ObjectBuildableFactory;
import java.util.Map;
@@ -54,12 +54,22 @@ public void setQuirks(Quirks quirks) {
this.quirks = quirks;
}
-
-
- @SuppressWarnings("unchecked")
public ResultSetHandlerFactory newFactory(Class clazz) {
- PojoMetadata pojoMetadata = new PojoMetadata(clazz, caseSensitive, autoDeriveColumnNames, columnMappings, throwOnMappingError);
- return new DefaultResultSetHandlerFactory(pojoMetadata, quirks);
+
+ return new DefaultResultSetHandlerFactory<>(() -> {
+ try {
+ return ObjectBuildableFactory.forClass(
+ clazz,
+ new Settings(
+ new NamingConvention(caseSensitive, autoDeriveColumnNames),
+ quirks,
+ throwOnMappingError),
+ getColumnMappings()
+ );
+ } catch (ReflectiveOperationException e) {
+ throw new Sql2oException("Error while trying to construct object from class " + clazz, e);
+ }
+ }, quirks);
}
}
diff --git a/core/src/main/java/org/sql2o/NamingConvention.java b/core/src/main/java/org/sql2o/NamingConvention.java
new file mode 100644
index 00000000..31f216d5
--- /dev/null
+++ b/core/src/main/java/org/sql2o/NamingConvention.java
@@ -0,0 +1,28 @@
+package org.sql2o;
+
+import org.sql2o.tools.SnakeToCamelCase;
+
+import java.util.Map;
+
+public class NamingConvention {
+
+ private final boolean caseSensitive;
+ private final boolean autoDeriveColumnNames;
+
+ public NamingConvention(boolean caseSensitive, boolean autoDeriveColumnNames) {
+ this.caseSensitive = caseSensitive;
+ this.autoDeriveColumnNames = autoDeriveColumnNames;
+ }
+
+ public String deriveName(String name) {
+ var derivedName = name;
+
+ if (autoDeriveColumnNames) {
+ derivedName = SnakeToCamelCase.convert(derivedName);
+ }
+ if (!caseSensitive)
+ derivedName = derivedName.toLowerCase();
+
+ return derivedName;
+ }
+}
diff --git a/core/src/main/java/org/sql2o/Query.java b/core/src/main/java/org/sql2o/Query.java
index b1929f01..cb50bbe2 100644
--- a/core/src/main/java/org/sql2o/Query.java
+++ b/core/src/main/java/org/sql2o/Query.java
@@ -9,7 +9,7 @@
import org.sql2o.logging.LocalLoggerFactory;
import org.sql2o.logging.Logger;
import org.sql2o.quirks.Quirks;
-import org.sql2o.reflection.PojoIntrospector;
+import org.sql2o.reflection2.PojoIntrospector;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
diff --git a/core/src/main/java/org/sql2o/Settings.java b/core/src/main/java/org/sql2o/Settings.java
new file mode 100644
index 00000000..278ba02b
--- /dev/null
+++ b/core/src/main/java/org/sql2o/Settings.java
@@ -0,0 +1,28 @@
+package org.sql2o;
+
+import org.sql2o.quirks.Quirks;
+
+public class Settings {
+
+ private final Quirks quirks;
+ private final NamingConvention namingConvention;
+ private final boolean throwOnMappingError;
+
+ public Settings(NamingConvention namingConvention, Quirks quirks, boolean throwOnMappingError) {
+ this.quirks = quirks;
+ this.namingConvention = namingConvention;
+ this.throwOnMappingError = throwOnMappingError;
+ }
+
+ public Quirks getQuirks() {
+ return quirks;
+ }
+
+ public NamingConvention getNamingConvention() {
+ return namingConvention;
+ }
+
+ public boolean isThrowOnMappingError(){
+ return throwOnMappingError;
+ }
+}
diff --git a/core/src/main/java/org/sql2o/converters/Convert.java b/core/src/main/java/org/sql2o/converters/Convert.java
index b4ac71c7..ef5d1f2d 100644
--- a/core/src/main/java/org/sql2o/converters/Convert.java
+++ b/core/src/main/java/org/sql2o/converters/Convert.java
@@ -11,8 +11,6 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
@@ -127,17 +125,12 @@ public static Converter throwIfNull(Class clazz, Converter converte
}
public static Converter getConverterIfExists(Class clazz) {
- Converter c;
- rl.lock();
- try {
- c = registeredConverters.get(clazz);
- } finally {
- rl.unlock();
- }
+ final var c = (Converter)registeredConverters.get(clazz);
+
if (c != null) return c;
if (clazz.isEnum()) {
- return registeredEnumConverterFactory.newConverter((Class) clazz);
+ return registeredEnumConverterFactory.newConverter((Class)clazz);
}
return null;
}
diff --git a/core/src/main/java/org/sql2o/converters/DefaultConverter.java b/core/src/main/java/org/sql2o/converters/DefaultConverter.java
new file mode 100644
index 00000000..ae8722a2
--- /dev/null
+++ b/core/src/main/java/org/sql2o/converters/DefaultConverter.java
@@ -0,0 +1,8 @@
+package org.sql2o.converters;
+
+public class DefaultConverter extends ConverterBase