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 { + @Override + public Object convert(Object val) throws ConverterException { + return val; + } +} diff --git a/core/src/main/java/org/sql2o/converters/IntegerConverter.java b/core/src/main/java/org/sql2o/converters/IntegerConverter.java index 6f24d4c1..09e6f550 100644 --- a/core/src/main/java/org/sql2o/converters/IntegerConverter.java +++ b/core/src/main/java/org/sql2o/converters/IntegerConverter.java @@ -11,6 +11,9 @@ public IntegerConverter(boolean primitive) { @Override protected Integer convertNumberValue(Number val) { + if (val instanceof Integer intVal) { + return intVal; + } return val.intValue(); } diff --git a/core/src/main/java/org/sql2o/converters/NumberConverter.java b/core/src/main/java/org/sql2o/converters/NumberConverter.java index a20f023f..28118625 100644 --- a/core/src/main/java/org/sql2o/converters/NumberConverter.java +++ b/core/src/main/java/org/sql2o/converters/NumberConverter.java @@ -5,7 +5,7 @@ */ public abstract class NumberConverter extends ConverterBase { - private boolean isPrimitive; + private final boolean isPrimitive; public NumberConverter(boolean primitive) { isPrimitive = primitive; @@ -16,23 +16,16 @@ public V convert(Object val) { return isPrimitive ? convertNumberValue(0) : null; } - // val.getClass().isPrimitive() is ALWAYS false - // since boxing (i.e. Object val=(int)1;) - // changes type from Integet.TYPE to Integer.class - // learn 2 java :) - - else if (/*val.getClass().isPrimitive() || */val instanceof Number ) { - return convertNumberValue((Number)val); + else if (val instanceof Number num) { + return convertNumberValue(num); } - else if (val instanceof String){ - String stringVal = ((String)val).trim(); - stringVal = stringVal.isEmpty() ? null : stringVal; + else if (val instanceof String strVal){ + strVal = strVal.trim(); - if (stringVal == null) { + if (strVal.isEmpty()) { return isPrimitive ? convertNumberValue(0) : null; } - - return convertStringValue(stringVal); + return convertStringValue(strVal); } else{ throw new IllegalArgumentException("Cannot convert type " + val.getClass().toString() + " to " + getTypeDescription()); diff --git a/core/src/main/java/org/sql2o/converters/StringConverter.java b/core/src/main/java/org/sql2o/converters/StringConverter.java index 6378f3de..e51f9fea 100644 --- a/core/src/main/java/org/sql2o/converters/StringConverter.java +++ b/core/src/main/java/org/sql2o/converters/StringConverter.java @@ -17,6 +17,10 @@ public String convert(Object val) throws ConverterException { return null; } + if (val instanceof String stringVal){ + return stringVal; + } + if (val instanceof Clob) { Clob clobVal = (Clob)val; try diff --git a/core/src/main/java/org/sql2o/data/Row.java b/core/src/main/java/org/sql2o/data/Row.java index 9d469405..8eef7afb 100644 --- a/core/src/main/java/org/sql2o/data/Row.java +++ b/core/src/main/java/org/sql2o/data/Row.java @@ -143,13 +143,11 @@ public String getString(String columnName){ * View row as a simple map. */ public Map asMap() { - Map map = new HashMap(); + final var map = new HashMap(); Set keys = columnNameToIdxMap.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - String colum = iterator.next().toString(); - int index = columnNameToIdxMap.get(colum); - map.put(colum, values[index]); + for (String key : keys) { + int index = columnNameToIdxMap.get(key); + map.put(key, values[index]); } return map; } diff --git a/core/src/main/java/org/sql2o/quirks/NoQuirks.java b/core/src/main/java/org/sql2o/quirks/NoQuirks.java index c2678075..dd7cd467 100644 --- a/core/src/main/java/org/sql2o/quirks/NoQuirks.java +++ b/core/src/main/java/org/sql2o/quirks/NoQuirks.java @@ -2,6 +2,7 @@ import org.sql2o.converters.Convert; import org.sql2o.converters.Converter; +import org.sql2o.converters.DefaultConverter; import org.sql2o.quirks.parameterparsing.SqlParameterParsingStrategy; import org.sql2o.quirks.parameterparsing.impl.DefaultSqlParameterParsingStrategy; @@ -35,9 +36,19 @@ public NoQuirks() { public Converter converterOf(Class ofClass) { // if nobody change this collection outside constructor // it's thread-safe - Converter c = converters.get(ofClass); + var c = converters.get(ofClass); + // if no "local" converter let's look in global - return c!=null?c:Convert.getConverterIfExists(ofClass); + if (c == null) { + c = Convert.getConverterIfExists(ofClass); + } + + // Fall back to the default converter + if (c == null) { + c = new DefaultConverter(); + } + + return c; } diff --git a/core/src/main/java/org/sql2o/reflection/FactoryFacade.java b/core/src/main/java/org/sql2o/reflection/FactoryFacade.java deleted file mode 100644 index 91d194dd..00000000 --- a/core/src/main/java/org/sql2o/reflection/FactoryFacade.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -@SuppressWarnings("Unsafe") -public class FactoryFacade { - private final static FactoryFacade instance; - - static { - MethodGetterFactory mg = new ReflectionMethodGetterFactory(); - MethodSetterFactory m = new ReflectionMethodSetterFactory(); - ObjectConstructorFactory o = new ReflectionObjectConstructorFactory(); -// try { -// m = (MethodSetterFactory) Class -// .forName("org.sql2o.reflection.MethodAccessorsGenerator") -// .newInstance(); -// mg = (MethodGetterFactory) m; -// o = (ObjectConstructorFactory) m; -// } catch (Throwable ex) { -// mg = new ReflectionMethodGetterFactory(); -// m = new ReflectionMethodSetterFactory(); -// o = null; -// } - FieldGetterFactory fg = new ReflectionFieldGetterFactory(); - FieldSetterFactory f = new ReflectionFieldSetterFactory(); -// try { -// Class clsg = Class.forName("org.sql2o.reflection.UnsafeFieldGetterFactory"); -// fg = (FieldGetterFactory) clsg.newInstance(); -// Class cls = Class.forName("org.sql2o.reflection.UnsafeFieldSetterFactory"); -// f = (FieldSetterFactory) cls.newInstance(); -// if(o==null) o = (ObjectConstructorFactory) f; -// } catch (Throwable ex) { -// fg = new ReflectionFieldGetterFactory(); -// f = new ReflectionFieldSetterFactory(); -// o = new ReflectionObjectConstructorFactory(); -// } - instance = new FactoryFacade(fg, mg, f, m, o); - } - - private final FieldGetterFactory fieldGetterFactory; - private final MethodGetterFactory methodGetterFactory; - private final FieldSetterFactory fieldSetterFactory; - private final MethodSetterFactory methodSetterFactory; - private final ObjectConstructorFactory objectConstructorFactory; - - public FactoryFacade( - FieldGetterFactory fieldGetterFactory, MethodGetterFactory methodGetterFactory, - FieldSetterFactory fieldSetterFactory, MethodSetterFactory methodSetterFactory, - ObjectConstructorFactory objectConstructorFactory) { - - this.fieldGetterFactory = fieldGetterFactory; - this.methodGetterFactory = methodGetterFactory; - this.fieldSetterFactory = fieldSetterFactory; - this.methodSetterFactory = methodSetterFactory; - this.objectConstructorFactory = objectConstructorFactory; - } - - public static FactoryFacade getInstance() { - return instance; - } - - public Getter newGetter(Field field) { - return fieldGetterFactory.newGetter(field); - } - - public Getter newGetter(Method method) { - return methodGetterFactory.newGetter(method); - } - - public Setter newSetter(Field field) { - return fieldSetterFactory.newSetter(field); - } - - public Setter newSetter(Method method) { - return methodSetterFactory.newSetter(method); - } - - public ObjectConstructor newConstructor(Class cls) { - return objectConstructorFactory.newConstructor(cls); - } -} - diff --git a/core/src/main/java/org/sql2o/reflection/FieldGetter.java b/core/src/main/java/org/sql2o/reflection/FieldGetter.java deleted file mode 100644 index 4e0af874..00000000 --- a/core/src/main/java/org/sql2o/reflection/FieldGetter.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; - -import java.lang.reflect.Field; - -/** - * used internally to get property values directly from the field. Only used if no getter method is found. - * - * @author mdelapenya - */ -public class FieldGetter implements Getter { - - private Field field; - - public FieldGetter(Field field) { - this.field = field; - this.field.setAccessible(true); - } - - public Object getProperty(Object obj) { - try { - return this.field.get(obj); - } catch (IllegalAccessException e) { - throw new Sql2oException("could not get field " + this.field.getName() + " on class " + obj.getClass().toString(), e); - } - } - - public Class getType() { - return field.getType(); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection/FieldGetterFactory.java b/core/src/main/java/org/sql2o/reflection/FieldGetterFactory.java deleted file mode 100644 index 420bd7bb..00000000 --- a/core/src/main/java/org/sql2o/reflection/FieldGetterFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Field; - -/** - * @author mdelapenya - */ -public interface FieldGetterFactory { - Getter newGetter(Field field); -} \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection/FieldSetter.java b/core/src/main/java/org/sql2o/reflection/FieldSetter.java deleted file mode 100644 index 31af9d97..00000000 --- a/core/src/main/java/org/sql2o/reflection/FieldSetter.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; - -import java.lang.reflect.Field; - -/** - * used internally to set property values directly into the field. Only used if no setter method is found. - */ -public class FieldSetter implements Setter{ - - private Field field; - - public FieldSetter(Field field) { - this.field = field; - this.field.setAccessible(true); - } - - public void setProperty(Object obj, Object value) { - if (value == null && this.field.getType().isPrimitive()){ - return; // dont try set null to a primitive field - } - - try { - this.field.set(obj, value); - } catch (IllegalAccessException e) { - throw new Sql2oException("could not set field " + this.field.getName() + " on class " + obj.getClass().toString(), e); - } - } - - public Class getType() { - return field.getType(); - } -} diff --git a/core/src/main/java/org/sql2o/reflection/FieldSetterFactory.java b/core/src/main/java/org/sql2o/reflection/FieldSetterFactory.java deleted file mode 100644 index cf00bdbc..00000000 --- a/core/src/main/java/org/sql2o/reflection/FieldSetterFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Field; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 12:39 AM - * To change this template use File | Settings | File Templates. - */ -public interface FieldSetterFactory { - Setter newSetter(Field field); -} diff --git a/core/src/main/java/org/sql2o/reflection/Getter.java b/core/src/main/java/org/sql2o/reflection/Getter.java deleted file mode 100644 index 246a11d3..00000000 --- a/core/src/main/java/org/sql2o/reflection/Getter.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflection; - -/** - * The Getter interface is used by sql2o to get property values when doing automatic column to property mapping - * - * @author mdelapenya - */ -public interface Getter { - - Object getProperty(Object obj); - Class getType(); -} diff --git a/core/src/main/java/org/sql2o/reflection/MethodGetter.java b/core/src/main/java/org/sql2o/reflection/MethodGetter.java deleted file mode 100644 index 6de543f4..00000000 --- a/core/src/main/java/org/sql2o/reflection/MethodGetter.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * used internally to get property values via its getter method. - * - * @author mdelapenya - */ -public class MethodGetter implements Getter { - - private Method method; - private Class type; - - public MethodGetter(Method method) { - this.method = method; - this.method.setAccessible(true); - type = method.getReturnType(); - } - - public Object getProperty(Object obj) { - try { - return this.method.invoke(obj); - } catch (IllegalAccessException e) { - throw new Sql2oException("error while calling getter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); - } catch (InvocationTargetException e) { - throw new Sql2oException("error while calling getter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); - } - } - - public Class getType() { - return type; - } -} diff --git a/core/src/main/java/org/sql2o/reflection/MethodGetterFactory.java b/core/src/main/java/org/sql2o/reflection/MethodGetterFactory.java deleted file mode 100644 index e1950000..00000000 --- a/core/src/main/java/org/sql2o/reflection/MethodGetterFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Method; - -/** - * @author mdelapenya - */ -public interface MethodGetterFactory { - Getter newGetter(Method method); -} \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection/MethodSetter.java b/core/src/main/java/org/sql2o/reflection/MethodSetter.java deleted file mode 100644 index e2704319..00000000 --- a/core/src/main/java/org/sql2o/reflection/MethodSetter.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * used internally to set property values via its setter method. - */ -public class MethodSetter implements Setter{ - - private Method method; - private Class type; - - public MethodSetter(Method method) { - this.method = method; - this.method.setAccessible(true); - type = method.getParameterTypes()[0]; - } - - public void setProperty(Object obj, Object value) { - if (value == null && type.isPrimitive()){ - return; // dont try to set null to a setter to a primitive type. - } - try { - this.method.invoke(obj, value); - } catch (IllegalAccessException e) { - throw new Sql2oException("error while calling setter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); - } catch (InvocationTargetException e) { - throw new Sql2oException("error while calling setter method with name " + method.getName() + " on class " + obj.getClass().toString(), e); - } - } - - public Class getType() { - return type; - } -} diff --git a/core/src/main/java/org/sql2o/reflection/MethodSetterFactory.java b/core/src/main/java/org/sql2o/reflection/MethodSetterFactory.java deleted file mode 100644 index d1afc653..00000000 --- a/core/src/main/java/org/sql2o/reflection/MethodSetterFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Method; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 12:42 AM - * To change this template use File | Settings | File Templates. - */ -public interface MethodSetterFactory { - Setter newSetter(Method method); -} diff --git a/core/src/main/java/org/sql2o/reflection/ObjectConstructor.java b/core/src/main/java/org/sql2o/reflection/ObjectConstructor.java deleted file mode 100644 index 5538a47d..00000000 --- a/core/src/main/java/org/sql2o/reflection/ObjectConstructor.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflection; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 1:26 AM - * To change this template use File | Settings | File Templates. - */ -public interface ObjectConstructor { - Object newInstance(); -} diff --git a/core/src/main/java/org/sql2o/reflection/ObjectConstructorFactory.java b/core/src/main/java/org/sql2o/reflection/ObjectConstructorFactory.java deleted file mode 100644 index 82180f4d..00000000 --- a/core/src/main/java/org/sql2o/reflection/ObjectConstructorFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflection; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 1:27 AM - * To change this template use File | Settings | File Templates. - */ -public interface ObjectConstructorFactory { - ObjectConstructor newConstructor(Class cls); -} diff --git a/core/src/main/java/org/sql2o/reflection/Pojo.java b/core/src/main/java/org/sql2o/reflection/Pojo.java deleted file mode 100644 index d0d00a8a..00000000 --- a/core/src/main/java/org/sql2o/reflection/Pojo.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.sql2o.reflection; - -import static org.sql2o.converters.Convert.throwIfNull; - -import org.sql2o.Sql2oException; -import org.sql2o.converters.Converter; -import org.sql2o.converters.ConverterException; -import org.sql2o.quirks.Quirks; - -/** - * Used internally to represent a plain old java object. - */ -public class Pojo { - - private PojoMetadata metadata; - private boolean caseSensitive; - private Object object; - - public Pojo(PojoMetadata metadata, boolean caseSensitive, Object object){ - this.caseSensitive = caseSensitive; - this.metadata = metadata; - this.object = object; - } - - public Pojo(PojoMetadata metadata, boolean caseSensitive){ - this.caseSensitive = caseSensitive; - this.metadata = metadata; - ObjectConstructor objectConstructor = metadata.getObjectConstructor(); - object = objectConstructor.newInstance(); - } - - @SuppressWarnings("unchecked") - public void setProperty(String propertyPath, Object value, Quirks quirks){ - // String.split uses RegularExpression - // this is overkill for every column for every row - int index = propertyPath.indexOf('.'); - Setter setter; - if (index > 0){ - final String substring = propertyPath.substring(0, index); - setter = metadata.getPropertySetter(substring); - String newPath = propertyPath.substring(index+1); - - Object subValue = this.metadata.getValueOfProperty(substring, this.object); - if (subValue == null){ - try { - subValue = setter.getType().newInstance(); - } catch (InstantiationException e) { - throw new Sql2oException("Could not instantiate a new instance of class "+ setter.getType().toString(), e); - } catch (IllegalAccessException e) { - throw new Sql2oException("Could not instantiate a new instance of class "+ setter.getType().toString(), e); - } - setter.setProperty(this.object, subValue); - } - - PojoMetadata subMetadata = new PojoMetadata(setter.getType(), this.caseSensitive, this.metadata.isAutoDeriveColumnNames(), this.metadata.getColumnMappings(), this.metadata.throwOnMappingFailure); - Pojo subPojo = new Pojo(subMetadata, this.caseSensitive, subValue); - subPojo.setProperty(newPath, value, quirks); - } - else{ - setter = metadata.getPropertySetter(propertyPath); - Converter converter; - try { - converter = throwIfNull(setter.getType(), quirks.converterOf(setter.getType())); - } catch (ConverterException e) { - throw new Sql2oException("Cannot convert column " + propertyPath + " to type " + setter.getType(), e); - } - - try { - setter.setProperty(this.object, converter.convert( value )); - } catch (ConverterException e) { - throw new Sql2oException("Error trying to convert column " + propertyPath + " to type " + setter.getType(), e); - } - } - - - } - - - - public Object getObject(){ - return this.object; - } - -} diff --git a/core/src/main/java/org/sql2o/reflection/PojoMetadata.java b/core/src/main/java/org/sql2o/reflection/PojoMetadata.java deleted file mode 100644 index f67c6b88..00000000 --- a/core/src/main/java/org/sql2o/reflection/PojoMetadata.java +++ /dev/null @@ -1,267 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; -import org.sql2o.tools.AbstractCache; -import org.sql2o.tools.UnderscoreToCamelCase; - -import javax.persistence.Column; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * Stores metadata for a POJO. - */ -public class PojoMetadata { - - private static final Cache caseSensitiveFalse = new Cache(); - private static final Cache caseSensitiveTrue = new Cache(); - private final PropertyAndFieldInfo propertyInfo; - private final Map columnMappings; - private final FactoryFacade factoryFacade = FactoryFacade.getInstance(); - - private boolean caseSensitive; - private boolean autoDeriveColumnNames; - public final boolean throwOnMappingFailure; - private Class clazz; - - public boolean isCaseSensitive() { - return caseSensitive; - } - - public boolean isAutoDeriveColumnNames() { - return autoDeriveColumnNames; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PojoMetadata that = (PojoMetadata) o; - - return autoDeriveColumnNames == that.autoDeriveColumnNames - && caseSensitive == that.caseSensitive - && clazz.equals(that.clazz) - && columnMappings.equals(that.columnMappings) - && propertyInfo.equals(that.propertyInfo); - - } - - @Override - public int hashCode() { - int result = (caseSensitive ? 1 : 0); - result = 31 * result + clazz.hashCode(); - return result; - } - - public PojoMetadata(Class clazz, boolean caseSensitive, boolean autoDeriveColumnNames, Map columnMappings, boolean throwOnMappingError) { - this.caseSensitive = caseSensitive; - this.autoDeriveColumnNames = autoDeriveColumnNames; - this.clazz = clazz; - this.columnMappings = columnMappings == null ? Collections.emptyMap() : columnMappings; - - this.propertyInfo = getPropertyInfoThroughCache(); - this.throwOnMappingFailure = throwOnMappingError; - - } - - public ObjectConstructor getObjectConstructor() { - return propertyInfo.objectConstructor; - } - - private PropertyAndFieldInfo getPropertyInfoThroughCache() { - return (caseSensitive - ? caseSensitiveTrue - : caseSensitiveFalse) - .get(clazz, this); - } - - private PropertyAndFieldInfo initializePropertyInfo() { - - HashMap propertyGetters = new HashMap(); - HashMap propertySetters = new HashMap(); - HashMap fields = new HashMap(); - - boolean isJpaColumnInClasspath = false; - try { - Class.forName("javax.persistence.Column"); - isJpaColumnInClasspath = true; - } catch (ClassNotFoundException e) { - // javax.persistence.Column is not in the classpath - } - - Class theClass = clazz; - ObjectConstructor objectConstructor = factoryFacade.newConstructor(theClass); - do { - for (Field f : theClass.getDeclaredFields()) { - if(Modifier.isStatic(f.getModifiers())) { - continue; - } - String propertyName = readAnnotatedColumnName(f, isJpaColumnInClasspath); - if(propertyName == null) { - propertyName = f.getName(); - } - propertyName = caseSensitive ? propertyName : propertyName.toLowerCase(); - - propertyGetters.put(propertyName, factoryFacade.newGetter(f)); - propertySetters.put(propertyName, factoryFacade.newSetter(f)); - fields.put(propertyName, f); - } - - // prepare methods. Methods will override fields, if both exists. - for (Method m : theClass.getDeclaredMethods()) { - - if (m.getName().startsWith("get")) { - String propertyName = m.getName().substring(3); - if (caseSensitive) { - propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); - } else { - propertyName = propertyName.toLowerCase(); - } - - propertyGetters.put(propertyName, factoryFacade.newGetter(m)); - } - - if (m.getName().startsWith("set") && m.getParameterTypes().length == 1) { - String propertyName = readAnnotatedColumnName(m, isJpaColumnInClasspath); - if(propertyName == null) { - propertyName = m.getName().substring(3); - } - if (caseSensitive) { - propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); - } else { - propertyName = propertyName.toLowerCase(); - } - - propertySetters.put(propertyName, factoryFacade.newSetter(m)); - } - } - theClass = theClass.getSuperclass(); - } while (!theClass.equals(Object.class)); - - return new PropertyAndFieldInfo(propertyGetters, propertySetters, fields, objectConstructor); - - } - - public Map getColumnMappings() { - return columnMappings; - } - - public Getter getPropertyGetter(String propertyName) { - - Getter getter = getPropertyGetterIfExists(propertyName); - - if (getter != null) { - return getter; - } else { - String errorMsg = "Property with name '" + propertyName + "' not found on class " + this.clazz.toString(); - if (this.caseSensitive) { - errorMsg += " (You have turned on case sensitive property search. Is this intentional?)"; - } - throw new Sql2oException(errorMsg); - } - } - - public Getter getPropertyGetterIfExists(String propertyName) { - - String name = this.caseSensitive ? propertyName : propertyName.toLowerCase(); - - if (this.columnMappings.containsKey(name)) { - name = this.columnMappings.get(name); - } - - if (autoDeriveColumnNames) { - name = UnderscoreToCamelCase.convert(name); - if (!this.caseSensitive) name = name.toLowerCase(); - } - - return propertyInfo.propertyGetters.get(name); - } - - public Setter getPropertySetter(String propertyName) { - - Setter setter = getPropertySetterIfExists(propertyName); - - if (setter != null) { - return setter; - } else { - String errorMsg = "Property with name '" + propertyName + "' not found on class " + this.clazz.toString(); - if (this.caseSensitive) { - errorMsg += " (You have turned on case sensitive property search. Is this intentional?)"; - } - throw new Sql2oException(errorMsg); - } - } - - public Setter getPropertySetterIfExists(String propertyName) { - - String name = this.caseSensitive ? propertyName : propertyName.toLowerCase(); - - if (this.columnMappings.containsKey(name)) { - name = this.columnMappings.get(name); - } - - if (autoDeriveColumnNames) { - name = UnderscoreToCamelCase.convert(name); - if (!this.caseSensitive) name = name.toLowerCase(); - } - - return propertyInfo.propertySetters.get(name); - } - - public Class getType() { - return this.clazz; - } - - public Object getValueOfProperty(String propertyName, Object object) { - Getter getter = getPropertyGetter(propertyName); - - return getter.getProperty(object); - } - - /** - * Try to read the {@link javax.persistence.Column} annotation and return the name of the column. - * Returns null if no {@link javax.persistence.Column} annotation is present or if the name of the column is empty - */ - private String readAnnotatedColumnName(AnnotatedElement classMember, boolean isJpaColumnInClasspath) { - if(isJpaColumnInClasspath) { - Column columnInformation = classMember.getAnnotation(Column.class); - if(columnInformation != null && columnInformation.name() != null && !columnInformation.name().isEmpty()) { - return columnInformation.name(); - } - } - return null; - } - - private static class Cache extends AbstractCache { - @Override - protected PropertyAndFieldInfo evaluate(Class key, PojoMetadata param) { - return param.initializePropertyInfo(); - } - } - - private static class PropertyAndFieldInfo { - // since this class is private we can just use field access - // to make HotSpot a little less work for inlining - public final Map propertyGetters; - public final Map propertySetters; - public final Map fields; - public final ObjectConstructor objectConstructor; - - private PropertyAndFieldInfo( - Map propertyGetters, Map propertySetters, - Map fields, ObjectConstructor objectConstructor) { - - this.propertyGetters = propertyGetters; - this.propertySetters = propertySetters; - this.fields = fields; - this.objectConstructor = objectConstructor; - } - } -} - diff --git a/core/src/main/java/org/sql2o/reflection/ReflectionFieldGetterFactory.java b/core/src/main/java/org/sql2o/reflection/ReflectionFieldGetterFactory.java deleted file mode 100644 index 0dd507a2..00000000 --- a/core/src/main/java/org/sql2o/reflection/ReflectionFieldGetterFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Field; - -/** - * @author mdelapenya - */ -public class ReflectionFieldGetterFactory implements FieldGetterFactory { - public Getter newGetter(Field field) { - return new FieldGetter(field); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection/ReflectionFieldSetterFactory.java b/core/src/main/java/org/sql2o/reflection/ReflectionFieldSetterFactory.java deleted file mode 100644 index 72454433..00000000 --- a/core/src/main/java/org/sql2o/reflection/ReflectionFieldSetterFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Field; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 12:40 AM - * To change this template use File | Settings | File Templates. - */ -public class ReflectionFieldSetterFactory implements FieldSetterFactory { - public Setter newSetter(Field field) { - return new FieldSetter(field); - } -} diff --git a/core/src/main/java/org/sql2o/reflection/ReflectionMethodGetterFactory.java b/core/src/main/java/org/sql2o/reflection/ReflectionMethodGetterFactory.java deleted file mode 100644 index c2b6b1b1..00000000 --- a/core/src/main/java/org/sql2o/reflection/ReflectionMethodGetterFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Method; - -/** - * @author mdelapenya - */ -public class ReflectionMethodGetterFactory implements MethodGetterFactory { - public Getter newGetter(Method method) { - return new MethodGetter(method); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection/ReflectionMethodSetterFactory.java b/core/src/main/java/org/sql2o/reflection/ReflectionMethodSetterFactory.java deleted file mode 100644 index 3115228f..00000000 --- a/core/src/main/java/org/sql2o/reflection/ReflectionMethodSetterFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.sql2o.reflection; - -import java.lang.reflect.Method; - -/** - * Created with IntelliJ IDEA. - * User: dimzon - * Date: 4/6/14 - * Time: 12:43 AM - * To change this template use File | Settings | File Templates. - */ -public class ReflectionMethodSetterFactory implements MethodSetterFactory { - public Setter newSetter(Method method) { - return new MethodSetter(method); - } -} diff --git a/core/src/main/java/org/sql2o/reflection/ReflectionObjectConstructorFactory.java b/core/src/main/java/org/sql2o/reflection/ReflectionObjectConstructorFactory.java deleted file mode 100644 index 589adc6f..00000000 --- a/core/src/main/java/org/sql2o/reflection/ReflectionObjectConstructorFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.sql2o.reflection; - -import org.sql2o.Sql2oException; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -public class ReflectionObjectConstructorFactory implements ObjectConstructorFactory { - public ObjectConstructor newConstructor(final Class clazz) { - try { - final Constructor ctor = clazz.getDeclaredConstructor(); - ctor.setAccessible(true); - return new ObjectConstructor() { - public Object newInstance() { - try { - return ctor.newInstance((Object[])null); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new Sql2oException("Could not create a new instance of class " + clazz, e); - } - } - }; - } catch (Throwable e) { - if (clazz.getEnclosingClass() == null) { - throw new Sql2oException("Could not find parameter-less constructor of class " + clazz, e); - } else { - throw new Sql2oException("Could not find parameter-less constructor of class " + clazz + ", if your pojo is a nested class, you could try to make it static.", e); - } - } - } -} diff --git a/core/src/main/java/org/sql2o/reflection/Setter.java b/core/src/main/java/org/sql2o/reflection/Setter.java deleted file mode 100644 index b7da73fe..00000000 --- a/core/src/main/java/org/sql2o/reflection/Setter.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sql2o.reflection; - -/** - * The Setter interface is used by sql2o to set property values when doing automatic column to property mapping - */ -public interface Setter { - - void setProperty(Object obj, Object value); - Class getType(); -} diff --git a/core/src/main/java/org/sql2o/reflection/package-info.java b/core/src/main/java/org/sql2o/reflection/package-info.java deleted file mode 100644 index b3e497f5..00000000 --- a/core/src/main/java/org/sql2o/reflection/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides the internal functionality used by sql2o to accomplish the automatic row to property mapping. - */ -package org.sql2o.reflection; \ No newline at end of file diff --git a/core/src/main/java/org/sql2o/reflection2/ObjectBuildable.java b/core/src/main/java/org/sql2o/reflection2/ObjectBuildable.java new file mode 100644 index 00000000..94e674a2 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/ObjectBuildable.java @@ -0,0 +1,8 @@ +package org.sql2o.reflection2; + +public interface ObjectBuildable { + + void withValue(String columnName, Object value) throws ReflectiveOperationException; + + T build() throws ReflectiveOperationException; +} diff --git a/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactory.java b/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactory.java new file mode 100644 index 00000000..caf14705 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactory.java @@ -0,0 +1,24 @@ +package org.sql2o.reflection2; + +import org.sql2o.Settings; +import org.sql2o.tools.Cache; + +import java.util.Map; + +public class ObjectBuildableFactory { + + private static final Cache, PojoMetadata> pojoMetadataCache = new Cache<>(); + + public static ObjectBuildable forClass(Class targetClass, Settings settings, Map columnMappings) throws ReflectiveOperationException { + + if (targetClass.isRecord()) { + return new RecordBuilder<>(targetClass, settings); + } + + //noinspection unchecked + final var pojoMetadata = (PojoMetadata) pojoMetadataCache.get(targetClass, () -> + new PojoMetadata<>(targetClass, settings)); + + return new PojoBuilder<>(settings, pojoMetadata, columnMappings); + } +} diff --git a/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactoryDelegate.java b/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactoryDelegate.java new file mode 100644 index 00000000..b4bdc675 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/ObjectBuildableFactoryDelegate.java @@ -0,0 +1,5 @@ +package org.sql2o.reflection2; + +public interface ObjectBuildableFactoryDelegate { + ObjectBuildable newObjectBuilder(); +} diff --git a/core/src/main/java/org/sql2o/reflection2/PojoBuilder.java b/core/src/main/java/org/sql2o/reflection2/PojoBuilder.java new file mode 100644 index 00000000..e2e41a41 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/PojoBuilder.java @@ -0,0 +1,67 @@ +package org.sql2o.reflection2; + +import org.sql2o.Settings; +import org.sql2o.Sql2oException; + +import java.util.Map; + +public class PojoBuilder implements ObjectBuildable { + + private final Settings settings; + private final PojoMetadata pojoMetadata; + private final T pojo; + private final Map columnMappings; + + public PojoBuilder(Settings settings, PojoMetadata pojoMetadata, Map columnMappings) throws ReflectiveOperationException { + this(settings, pojoMetadata, columnMappings, pojoMetadata.getConstructor().newInstance()); + } + + public PojoBuilder(Settings settings, PojoMetadata pojoMetadata, Map columnMappings, T pojo) { + this.settings = settings; + this.pojoMetadata = pojoMetadata; + this.columnMappings = columnMappings; + this.pojo = pojo; + } + + @Override + public void withValue(String columnName, Object obj) throws ReflectiveOperationException { + + final var dotIdx = columnName.indexOf('.'); + String derivedName = null; + if (dotIdx > 0) { + final var subName = columnName.substring(0, dotIdx); + derivedName = settings.getNamingConvention().deriveName(subName); + final var subProperty = pojoMetadata.getPojoProperty(derivedName, columnMappings); + final var newPath = columnName.substring(dotIdx + 1); + + var subObj = subProperty.getValue(this.pojo); + if (subObj == null) { + subObj = subProperty.initializeWithNewInstance(this.pojo); + subProperty.SetProperty(this.pojo, subObj); + } + + final var subPojoMetadata = new PojoMetadata<>(subObj.getClass(), settings); + final var subObjectBuilder = new PojoBuilder(settings, subPojoMetadata, columnMappings, subObj); + subObjectBuilder.withValue(newPath, obj); + obj = subObjectBuilder.build(); + } + + if (derivedName == null) { + derivedName = settings.getNamingConvention().deriveName(columnName); + } + final var pojoProperty = pojoMetadata.getPojoProperty(derivedName, columnMappings); + + if (pojoProperty == null) { + if (settings.isThrowOnMappingError()){ + throw new Sql2oException("Could not map " + columnName + " to any property."); + } + return; + } + pojoProperty.SetProperty(this.pojo, obj); + } + + @Override + public T build() throws ReflectiveOperationException { + return pojo; + } +} diff --git a/core/src/main/java/org/sql2o/reflection/PojoIntrospector.java b/core/src/main/java/org/sql2o/reflection2/PojoIntrospector.java similarity index 99% rename from core/src/main/java/org/sql2o/reflection/PojoIntrospector.java rename to core/src/main/java/org/sql2o/reflection2/PojoIntrospector.java index bfb1faa2..35d810b0 100644 --- a/core/src/main/java/org/sql2o/reflection/PojoIntrospector.java +++ b/core/src/main/java/org/sql2o/reflection2/PojoIntrospector.java @@ -1,4 +1,4 @@ -package org.sql2o.reflection; +package org.sql2o.reflection2; import org.sql2o.tools.AbstractCache; diff --git a/core/src/main/java/org/sql2o/reflection2/PojoMetadata.java b/core/src/main/java/org/sql2o/reflection2/PojoMetadata.java new file mode 100644 index 00000000..894551f1 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/PojoMetadata.java @@ -0,0 +1,136 @@ +package org.sql2o.reflection2; + +import org.sql2o.Settings; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// Helper class for the PojoBuilder class. This class contains cacheable metadata about the POJO class. +public class PojoMetadata { + + private final Constructor constructor; + private final Map pojoProperties; + private final Settings settings; + + public PojoMetadata(Class clazz, Settings settings) throws ReflectiveOperationException { + this.constructor = clazz.getDeclaredConstructor(); + this.constructor.setAccessible(true); + this.settings = settings; + + final var pojoPropertyBuilders = getPojoPropertyBuilders(clazz); + + final var pojoPropertiesStream = pojoPropertyBuilders.stream().map(PojoPropertyBuilder::build); + pojoProperties = + pojoPropertiesStream.collect(Collectors.toMap(PojoProperty::getName, p -> p)); + + // also associate the annotated name with the property + final var pojoPropertiesWithAnnotatedName = pojoProperties.values().stream() + .filter(p -> p.getAnnotatedName() != null).toList(); + pojoPropertiesWithAnnotatedName.forEach(p -> pojoProperties.put(p.getAnnotatedName(), p)); + } + + public Constructor getConstructor() { + return constructor; + } + + public PojoProperty getPojoProperty(String name, Map columnMappings) { + if (columnMappings.containsKey(name)) { + final var columnName = columnMappings.get(name); + if (pojoProperties.containsKey(columnName)) + return pojoProperties.get(columnName); + } + + return pojoProperties.getOrDefault(name, null); + } + + private List getPojoPropertyBuilders(Class clazz) { + final var pojoPropertyBuilders = new HashMap(); + initializeForClassRecursive(clazz, pojoPropertyBuilders); + return new ArrayList<>(pojoPropertyBuilders.values()); + } + + /*** + * This method fills the pojoPropertyBuilders parameter with instances of the PojoPropertyBuilder class, for each property in the class and its subclasses. + * @param clazz + * @param pojoPropertyBuilders + */ + private void initializeForClassRecursive(Class clazz, HashMap pojoPropertyBuilders) { + for (final var method : clazz.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + method.setAccessible(true); + final var methodName = method.getName(); + if (methodName.startsWith("get") && method.getParameterCount() == 0) { + final var propertyName = settings.getNamingConvention().deriveName(methodName.substring(3)); + pojoPropertyBuilders.computeIfAbsent(propertyName, name -> new PojoPropertyBuilder(name, settings)).withGetter(method); + } else if (methodName.startsWith("is") && method.getParameterCount() == 0) { + final var propertyName = settings.getNamingConvention().deriveName(methodName.substring(2)); + pojoPropertyBuilders.computeIfAbsent(propertyName, name -> new PojoPropertyBuilder(name, settings)).withGetter(method); + } else if (methodName.startsWith("set") && method.getParameterCount() == 1) { + final var propertyName = settings.getNamingConvention().deriveName(methodName.substring(3)); + pojoPropertyBuilders.computeIfAbsent(propertyName, name -> new PojoPropertyBuilder(name, settings)).withSetter(method); + } + + if (pojoPropertyBuilders.containsKey(methodName)){ + pojoPropertyBuilders.get(methodName).withAnnotatedName(deriveAnnotatedName(method)); + } + } + + for (final var field : clazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + final var fieldName = settings.getNamingConvention().deriveName(field.getName()); + pojoPropertyBuilders.computeIfAbsent(fieldName, name -> new PojoPropertyBuilder(name, settings)).withField(field); + + if (pojoPropertyBuilders.containsKey(fieldName)){ + pojoPropertyBuilders.get(fieldName).withAnnotatedName(deriveAnnotatedName(field)); + } + } + + // Recursively initialize for the superclass, except if the superclass is 'Object'. + final var superClass = clazz.getSuperclass(); + if (!superClass.equals(Object.class)) { + initializeForClassRecursive(superClass, pojoPropertyBuilders); + } + } + + private static String deriveAnnotatedName(Executable method) { + if (!isJavaxPersistenceColumnPresent()) + return null; + + final var columnAnnotation = method.getAnnotation(javax.persistence.Column.class); + if (columnAnnotation == null) return null; + return columnAnnotation.name(); + } + + private static String deriveAnnotatedName(Field field) { + if (!isJavaxPersistenceColumnPresent()) + return null; + + final var columnAnnotation = field.getAnnotation(javax.persistence.Column.class); + if (columnAnnotation == null) return null; + return columnAnnotation.name(); + } + + + private static Boolean javaxPersistenceColumnPresence = null; + private static boolean isJavaxPersistenceColumnPresent() { + if (javaxPersistenceColumnPresence != null) + return javaxPersistenceColumnPresence; + + try { + Class.forName("javax.persistence.Column"); + javaxPersistenceColumnPresence = true; + } catch (ClassNotFoundException e) { + javaxPersistenceColumnPresence = false; + } + + return javaxPersistenceColumnPresence; + } +} diff --git a/core/src/main/java/org/sql2o/reflection2/PojoProperty.java b/core/src/main/java/org/sql2o/reflection2/PojoProperty.java new file mode 100644 index 00000000..4566c562 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/PojoProperty.java @@ -0,0 +1,119 @@ +package org.sql2o.reflection2; + +import org.sql2o.Settings; +import org.sql2o.Sql2oException; +import org.sql2o.converters.ConverterException; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class PojoProperty { + + private final String name; + private final String annotatedName; + private final Method getter; + private final Method setter; + private final Field field; + private final Settings settings; + + public PojoProperty(String name, String annotatedName, Method getter, Method setter, Field field, Settings settings) { + this.name = name; + this.annotatedName = annotatedName; + this.getter = getter; + this.setter = setter; + this.field = field; + if (field != null) { + this.field.setAccessible(true); + } + + this.settings = settings; + } + + public String getName() { + return name; + } + + public String getAnnotatedName() { + return annotatedName; + } + + public void SetProperty(Object obj, Object value) throws ReflectiveOperationException { + if (setter != null) { + try { + final var propertyType = getSetterType(); + final var convertedValue = settings.getQuirks().converterOf(propertyType).convert(value); + if (convertedValue == null && propertyType.isPrimitive()) { + return; // don't try to set null to a setter to a primitive type. + } + setter.invoke(obj, convertedValue); + } catch (ConverterException ex) { + throw new Sql2oException("Error trying to convert value of type " + value.getClass().getName() + " to property " + name + " [" + setter.getName() + "] of type " + setter.getDeclaringClass(), ex); + } + return; + } + + if(field != null) { + try { + final var propertyType = field.getType(); + final var convertedValue = settings.getQuirks().converterOf(propertyType).convert(value); + if (convertedValue == null && propertyType.isPrimitive()) { + return; // don't try to set null to a field to a primitive type. + } + field.set(obj, convertedValue); + } catch (ConverterException ex) { + throw new Sql2oException("Error trying to convert value of type " + value.getClass().getName() + " to field " + name + " of type " + field.getDeclaringClass(), ex); + } + return; + } + + throw new Sql2oException("No setter or field found for property " + name); + } + + public Class getType() { + if (setter != null) { + return setter.getParameters()[0].getType(); + } else if (field != null) { + return field.getType(); + } + + throw new Sql2oException("Unexpected error. Could not get type of property " + getName()); + } + + // only used when setting complex types + public Object getValue(Object obj) throws ReflectiveOperationException { + if (getter != null) { + return getter.invoke(obj); + } else if (field != null) { + return field.get(obj); + } + + throw new Sql2oException("No getter or field found for property " + name); + } + + // only used when setting complex types + public Object initializeWithNewInstance(Object obj) throws ReflectiveOperationException { + if (setter != null) { + final var propertyType = setter.getParameters()[0].getType(); + // create new instance. Assume empty constructor. + final var instance = propertyType.getDeclaredConstructor().newInstance(); + setter.invoke(obj, instance); + return instance; + } else if (field != null) { + final var propertyType = field.getType(); + // create new instance. Assume empty constructor. + final var instance = propertyType.getDeclaredConstructor().newInstance(); + field.set(obj, instance); + return instance; + } + + throw new Sql2oException("Could not initialize property " + getName() + " no setter or field found."); + } + + private Class setterType = null; + private Class getSetterType() { + if (setterType == null) { + setterType = setter.getParameters()[0].getType(); + } + return setterType; + } +} diff --git a/core/src/main/java/org/sql2o/reflection2/PojoPropertyBuilder.java b/core/src/main/java/org/sql2o/reflection2/PojoPropertyBuilder.java new file mode 100644 index 00000000..938bf98a --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/PojoPropertyBuilder.java @@ -0,0 +1,41 @@ +package org.sql2o.reflection2; + +import org.sql2o.Settings; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class PojoPropertyBuilder { + + private Method getter; + private Method setter; + private Field field; + private String annotatedName; + private final String name; + private final Settings settings; + + public PojoPropertyBuilder(String name, Settings settings) { + this.name = name; + this.settings = settings; + } + + public void withGetter(Method getter) { + this.getter = getter; + } + + public void withSetter(Method setter) { + this.setter = setter; + } + + public void withField(Field field) { + this.field = field; + } + + public void withAnnotatedName(String annotatedName) { + this.annotatedName = annotatedName; + } + + public PojoProperty build() { + return new PojoProperty(name, annotatedName, getter, setter, field, settings); + } +} diff --git a/core/src/main/java/org/sql2o/reflection2/RecordBuilder.java b/core/src/main/java/org/sql2o/reflection2/RecordBuilder.java new file mode 100644 index 00000000..e0472eb8 --- /dev/null +++ b/core/src/main/java/org/sql2o/reflection2/RecordBuilder.java @@ -0,0 +1,56 @@ +package org.sql2o.reflection2; + +import org.sql2o.NamingConvention; +import org.sql2o.Settings; +import org.sql2o.Sql2oException; +import org.sql2o.converters.ConverterException; +import org.sql2o.quirks.Quirks; + +import java.lang.reflect.Constructor; +import java.util.LinkedHashMap; + +public class RecordBuilder implements ObjectBuildable{ + + private final Constructor constructor; + private final LinkedHashMap values = new LinkedHashMap<>(); + private final Settings settings; + + @SuppressWarnings("unchecked") + public RecordBuilder(Class recordClass, Settings settings) { + + this.constructor = (Constructor)recordClass.getDeclaredConstructors()[0]; + this.settings = settings; + + for (final var recordComponent : recordClass.getRecordComponents()) { + values.put(settings.getNamingConvention().deriveName(recordComponent.getName()), new RecordValue(recordComponent.getType())); + } + } + + @Override + public void withValue(String columnName, Object value) { + final var derivedName = settings.getNamingConvention().deriveName(columnName); + if (!values.containsKey(derivedName)) { + throw new IllegalArgumentException("No such field in record: " + columnName); + } + final var convVal = values.get(derivedName); + try { + convVal.value = settings.getQuirks().converterOf(convVal.type).convert(value); + } catch (ConverterException e) { + throw new Sql2oException("Error trying to convert column " + columnName + " to type " + convVal.type, e); + } + } + + @Override + public T build() throws ReflectiveOperationException { + return constructor.newInstance(values.values().stream().map(recordValue -> recordValue.value).toArray()); + } + + private static class RecordValue { + public Object value = null; + public final Class type; + + public RecordValue(Class type) { + this.type = type; + } + } +} diff --git a/core/src/main/java/org/sql2o/tools/Cache.java b/core/src/main/java/org/sql2o/tools/Cache.java new file mode 100644 index 00000000..80dd4647 --- /dev/null +++ b/core/src/main/java/org/sql2o/tools/Cache.java @@ -0,0 +1,43 @@ +package org.sql2o.tools; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class Cache { + private final Map cacheMap; + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + public Cache() { + cacheMap = new HashMap<>(); + } + + public Value get(Key key, Callable valueDelegate) { + Value value = cacheMap.get(key); + + if (value != null) { + return value; + } + + // If not in cache, create a write lock, create and cache the object, and return it. + lock.writeLock().lock(); + try { + // Recheck state because another thread might have acquired write lock and changed state before we did + value = cacheMap.get(key); + if (value == null) { + value = valueDelegate.call(); + cacheMap.put(key, value); + } + + return value; + + } catch (Exception e) { + throw new RuntimeException("Error while getting value from cache", e); + } finally { + lock.writeLock().unlock(); + } + } + +} diff --git a/core/src/main/java/org/sql2o/tools/UnderscoreToCamelCase.java b/core/src/main/java/org/sql2o/tools/SnakeToCamelCase.java similarity index 96% rename from core/src/main/java/org/sql2o/tools/UnderscoreToCamelCase.java rename to core/src/main/java/org/sql2o/tools/SnakeToCamelCase.java index 76777af6..33afd4d3 100644 --- a/core/src/main/java/org/sql2o/tools/UnderscoreToCamelCase.java +++ b/core/src/main/java/org/sql2o/tools/SnakeToCamelCase.java @@ -6,7 +6,7 @@ * @author ryancarlson * @author dimzon - complete rewrite */ -public class UnderscoreToCamelCase { +public class SnakeToCamelCase { public static String convert(String underscore){ if(underscore==null || underscore.isEmpty()) return underscore; return convert00(underscore); diff --git a/core/src/test/java/org/sql2o/Sql2oTest.java b/core/src/test/java/org/sql2o/Sql2oTest.java index 61893005..10ef478f 100644 --- a/core/src/test/java/org/sql2o/Sql2oTest.java +++ b/core/src/test/java/org/sql2o/Sql2oTest.java @@ -48,31 +48,6 @@ public Sql2oTest(DbType dbType, String testName) { super(dbType, testName); } - //@Test TODO. commented out. Can't get test to work without an application server. - public void testCreateSql2oFromJndi() throws Exception { - System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); - System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming"); - - InitialContext ic = new InitialContext(); - - ic.createSubcontext("java:"); - ic.createSubcontext("java:comp"); - ic.createSubcontext("java:comp/env"); - - JDBCDataSource datasource = new JDBCDataSource(); - datasource.setUrl(dbType.url); - datasource.setUser(dbType.user); - datasource.setPassword(dbType.pass); - - ic.bind("java:comp/env/Sql2o", datasource); - - System.out.println("Datasource initialized."); - - Sql2o jndiSql2o = new Sql2o("Sql2o"); - - assertTrue(jndiSql2o != null); - } - @Test public void testExecuteAndFetch(){ createAndFillUserTable(); @@ -634,11 +609,13 @@ public void testSuperPojo(){ @Test public void testComplexTypes(){ - ComplexEntity pojo = sql2o.createQuery("select 1 id, 1 \"entity.id\", 'something' \"entity.value\" from (values(0))").setName("testComplexTypes").executeAndFetchFirst(ComplexEntity.class); + try (final var connection = sql2o.open()) { + ComplexEntity pojo = connection.createQuery("select 1 id, 1 \"entity.id\", 'something' \"entity.value\" from (values(0))").setName("testComplexTypes").executeAndFetchFirst(ComplexEntity.class); - assertEquals(1, pojo.id); - assertEquals(1, pojo.getEntity().getId()); - assertEquals("something1", pojo.getEntity().getValue()); + assertEquals(1, pojo.id); + assertEquals(1, pojo.getEntity().getId()); + assertEquals("something1", pojo.getEntity().getValue()); + } } @Test diff --git a/core/src/test/java/org/sql2o/records/RecordsTest.java b/core/src/test/java/org/sql2o/records/RecordsTest.java new file mode 100644 index 00000000..ef81d764 --- /dev/null +++ b/core/src/test/java/org/sql2o/records/RecordsTest.java @@ -0,0 +1,56 @@ +package org.sql2o.records; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.sql2o.H2ArgumentsSourceProvider; +import org.sql2o.Sql2o; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RecordsTest { + + @ParameterizedTest(name = "{0}") + @ArgumentsSource(H2ArgumentsSourceProvider.class) + void deserializing_a_record_with_constructor_should_work(String dbName, String url, String user, String pass) { + // Arrange + final var sql2o = new Sql2o(url, user, pass); + createATableWithSomeData(sql2o); + + // Act + List recordResult; + try (final var con = sql2o.open()) { + recordResult = con.createQuery("SELECT id, name, is_ok as \"isOk\" FROM record_entity") + .executeAndFetch(RecordEntity.class); + } + + // Assert + assertEquals(2, recordResult.size()); + final var firstRecord = recordResult.get(0); + assertEquals(1, firstRecord.id()); + assertEquals("name1", firstRecord.name()); + assertTrue(firstRecord.isOk()); + } + + private void createATableWithSomeData(Sql2o sql2o){ + try (var con = sql2o.open()) { + con.createQuery("CREATE TABLE record_entity (id INT PRIMARY KEY, name VARCHAR(255), is_ok BOOLEAN)") + .executeUpdate(); + con.createQuery("INSERT INTO record_entity (id, name, is_ok) VALUES (:id, :name, :is_ok)") + .addParameter("id", 1) + .addParameter("name", "name1") + .addParameter("is_ok", true) + .executeUpdate(); + con.createQuery("INSERT INTO record_entity (id, name, is_ok) VALUES (:id, :name, :is_ok)") + .addParameter("id", 2) + .addParameter("name", "name2") + .addParameter("is_ok", false) + .executeUpdate(); + } + + } + + public record RecordEntity(int id, String name, boolean isOk) {} +} diff --git a/core/src/test/java/org/sql2o/reflect/AbstractFieldGetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/AbstractFieldGetterFactoryTest.java deleted file mode 100644 index 5db20d76..00000000 --- a/core/src/test/java/org/sql2o/reflect/AbstractFieldGetterFactoryTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.sql2o.reflect; - -import junit.framework.TestCase; -import org.sql2o.reflection.FieldGetterFactory; -import org.sql2o.reflection.Getter; - -import java.lang.reflect.Field; - -/** - * @author mdelapenya - */ -public abstract class AbstractFieldGetterFactoryTest extends TestCase { - public static class POJO1{ - boolean _boolean; - byte _byte; - short _short; - int _int; - long _long; - float _float; - double _double; - char _char; - Object _obj; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - - if (o == null || getClass() != o.getClass()) return false; - - POJO1 pojo1 = (POJO1) o; - - if (_boolean != pojo1._boolean) return false; - if (_byte != pojo1._byte) return false; - if (_char != pojo1._char) return false; - if (Double.compare(pojo1._double, _double) != 0) return false; - if (Float.compare(pojo1._float, _float) != 0) return false; - if (_int != pojo1._int) return false; - if (_long != pojo1._long) return false; - if (_short != pojo1._short) return false; - if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; - - return true; - } - } - - public void testAllTypes() throws IllegalAccessException { - POJO1 pojo = new POJO1(); - pojo._boolean = true; - pojo._byte = 17; - pojo._short=87; - pojo._int= Integer.MIN_VALUE; - pojo._long= 1337; - pojo._char='a'; - pojo._double=Math.PI; - pojo._float= (float) Math.log(93); - pojo._obj = pojo; - - Field[] fields = pojo.getClass().getDeclaredFields(); - - for (Field field : fields) { - Getter getter = fgf.newGetter(field); - assertSame(field.getType(),getter.getType()); - - Object val1 = field.get(pojo); - assertEquals(val1, getter.getProperty(pojo)); - } - } - - public final FieldGetterFactory fgf; - - protected AbstractFieldGetterFactoryTest(FieldGetterFactory fgf) { - this.fgf = fgf; - } -} \ No newline at end of file diff --git a/core/src/test/java/org/sql2o/reflect/AbstractFieldSetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/AbstractFieldSetterFactoryTest.java deleted file mode 100644 index c3b065bf..00000000 --- a/core/src/test/java/org/sql2o/reflect/AbstractFieldSetterFactoryTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.sql2o.reflect; - -import junit.framework.TestCase; -import org.sql2o.reflection.FieldSetterFactory; -import org.sql2o.reflection.Setter; - -import java.lang.reflect.Field; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 9:46 PM - */ -public abstract class AbstractFieldSetterFactoryTest extends TestCase { - public static class POJO1{ - boolean _boolean; - byte _byte; - short _short; - int _int; - long _long; - float _float; - double _double; - char _char; - Object _obj; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - POJO1 pojo1 = (POJO1) o; - - if (_boolean != pojo1._boolean) return false; - if (_byte != pojo1._byte) return false; - if (_char != pojo1._char) return false; - if (Double.compare(pojo1._double, _double) != 0) return false; - if (Float.compare(pojo1._float, _float) != 0) return false; - if (_int != pojo1._int) return false; - if (_long != pojo1._long) return false; - if (_short != pojo1._short) return false; - if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; - - return true; - } - } - - - public void testAllTypes() throws IllegalAccessException { - POJO1 pojo1 = new POJO1(); - pojo1._boolean = true; - pojo1._byte = 17; - pojo1._short=87; - pojo1._int= Integer.MIN_VALUE; - pojo1._long= 1337; - pojo1._char='a'; - pojo1._double=Math.PI; - pojo1._float= (float) Math.log(93); - pojo1._obj = pojo1; - - POJO1 pojo2 = new POJO1(); - - assertFalse(pojo1.equals(pojo2)); - - Field[] fields = pojo1.getClass().getDeclaredFields(); - for (Field field : fields) { - Setter setter = fsf.newSetter(field); - assertSame(field.getType(),setter.getType()); - Object val1 = field.get(pojo1); - Object val2 = field.get(pojo2); - assertFalse(val1.equals(val2)); - setter.setProperty(pojo2,val1); - Object val3 = field.get(pojo2); - assertEquals(val1,val3); - } - - assertEquals(pojo1,pojo2); - - // let's reset all values to NULL - // primitive fields will not be affected - for (Field field : fields) { - Setter setter = fsf.newSetter(field); - Object val1 = field.get(pojo1); - assertNotNull(val1); - - setter.setProperty(pojo1,null); - - Object val2 = field.get(pojo1); - if(!setter.getType().isPrimitive()){ - assertNull(val2); - continue; - } - assertNotNull(val2); - // not affected - assertEquals(val1,val2); - } - pojo2._obj = null; - assertEquals(pojo2,pojo1); - } - - - public final FieldSetterFactory fsf; - - protected AbstractFieldSetterFactoryTest(FieldSetterFactory fsf) { - this.fsf = fsf; - } -} diff --git a/core/src/test/java/org/sql2o/reflect/AbstractMethodGetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/AbstractMethodGetterFactoryTest.java deleted file mode 100644 index 39e97677..00000000 --- a/core/src/test/java/org/sql2o/reflect/AbstractMethodGetterFactoryTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.sql2o.reflect; - -import junit.framework.TestCase; -import org.sql2o.reflection.Getter; -import org.sql2o.reflection.MethodGetterFactory; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * @author mdelapenya - */ -public abstract class AbstractMethodGetterFactoryTest extends TestCase { - public static class POJO1{ - public boolean get_boolean() { - return this._boolean; - } - - public byte set_byte() { - return this._byte; - } - - public short set_short() { - return this._short; - } - - public int set_int() { - return this._int; - } - - public long set_long() { - return this._long; - } - - public float set_float() { - return this._float; - } - - public double set_double() { - return this._double; - } - - public char set_char() { - return this._char; - } - - public Object set_obj() { - return this._obj; - } - - boolean _boolean; - byte _byte; - short _short; - int _int; - long _long; - float _float; - double _double; - char _char; - Object _obj; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - POJO1 pojo1 = (POJO1) o; - - if (_boolean != pojo1._boolean) return false; - if (_byte != pojo1._byte) return false; - if (_char != pojo1._char) return false; - if (Double.compare(pojo1._double, _double) != 0) return false; - if (Float.compare(pojo1._float, _float) != 0) return false; - if (_int != pojo1._int) return false; - if (_long != pojo1._long) return false; - if (_short != pojo1._short) return false; - if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; - - return true; - } - } - - - public void testAllTypes() throws IllegalAccessException, NoSuchFieldException { - POJO1 pojo = new POJO1(); - pojo._boolean = true; - pojo._byte = 17; - pojo._short=87; - pojo._int= Integer.MIN_VALUE; - pojo._long= 1337; - pojo._char='a'; - pojo._double=Math.PI; - pojo._float= (float) Math.log(93); - pojo._obj = pojo; - - Method[] methods = pojo.getClass().getDeclaredMethods(); - for (Method method : methods) { - if(!method.getName().startsWith("get_")) continue; - - Field field = pojo.getClass() - .getDeclaredField(method.getName().substring(3)); - - Getter getter = mgf.newGetter(method); - assertSame(field.getType(),getter.getType()); - - Object val1 = field.get(pojo); - assertEquals(val1, getter.getProperty(pojo)); - } - } - - - public final MethodGetterFactory mgf; - - public AbstractMethodGetterFactoryTest(MethodGetterFactory mgf) { - this.mgf = mgf; - } -} \ No newline at end of file diff --git a/core/src/test/java/org/sql2o/reflect/AbstractMethodSetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/AbstractMethodSetterFactoryTest.java deleted file mode 100644 index 3838b8a7..00000000 --- a/core/src/test/java/org/sql2o/reflect/AbstractMethodSetterFactoryTest.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.sql2o.reflect; - -import junit.framework.TestCase; -import org.sql2o.reflection.MethodSetterFactory; -import org.sql2o.reflection.Setter; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 10:18 PM - */ -public abstract class AbstractMethodSetterFactoryTest extends TestCase { - public static class POJO1{ - public void set_boolean(boolean _boolean) { - this._boolean = _boolean; - } - - public void set_byte(byte _byte) { - this._byte = _byte; - } - - public void set_short(short _short) { - this._short = _short; - } - - public void set_int(int _int) { - this._int = _int; - } - - public void set_long(long _long) { - this._long = _long; - } - - public void set_float(float _float) { - this._float = _float; - } - - public void set_double(double _double) { - this._double = _double; - } - - public void set_char(char _char) { - this._char = _char; - } - - public void set_obj(Object _obj) { - this._obj = _obj; - } - - boolean _boolean; - byte _byte; - short _short; - int _int; - long _long; - float _float; - double _double; - char _char; - Object _obj; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - POJO1 pojo1 = (POJO1) o; - - if (_boolean != pojo1._boolean) return false; - if (_byte != pojo1._byte) return false; - if (_char != pojo1._char) return false; - if (Double.compare(pojo1._double, _double) != 0) return false; - if (Float.compare(pojo1._float, _float) != 0) return false; - if (_int != pojo1._int) return false; - if (_long != pojo1._long) return false; - if (_short != pojo1._short) return false; - if (_obj != null ? !_obj.equals(pojo1._obj) : pojo1._obj != null) return false; - - return true; - } - } - - - public void testAllTypes() throws IllegalAccessException, NoSuchFieldException { - POJO1 pojo1 = new POJO1(); - pojo1._boolean = true; - pojo1._byte = 17; - pojo1._short=87; - pojo1._int= Integer.MIN_VALUE; - pojo1._long= 1337; - pojo1._char='a'; - pojo1._double=Math.PI; - pojo1._float= (float) Math.log(93); - pojo1._obj = pojo1; - - POJO1 pojo2 = new POJO1(); - - assertFalse(pojo1.equals(pojo2)); - - Method[] methods = pojo1.getClass().getDeclaredMethods(); - for (Method method : methods) { - if(!method.getName().startsWith("set_")) continue; - Field field = pojo1.getClass() - .getDeclaredField(method.getName().substring(3)); - Setter setter = msf.newSetter(method); - assertSame(field.getType(),setter.getType()); - Object val1 = field.get(pojo1); - Object val2 = field.get(pojo2); - assertFalse(val1.equals(val2)); - setter.setProperty(pojo2,val1); - Object val3 = field.get(pojo2); - assertEquals(val1,val3); - } - - assertEquals(pojo1,pojo2); - - // let's reset all values to NULL - // primitive fields will not be affected - for (Method method : methods) { - if(!method.getName().startsWith("set_")) continue; - Field field = pojo1.getClass() - .getDeclaredField(method.getName().substring(3)); - Setter setter = msf.newSetter(method); - Object val1 = field.get(pojo1); - assertNotNull(val1); - - setter.setProperty(pojo1,null); - - Object val2 = field.get(pojo1); - if(!setter.getType().isPrimitive()){ - assertNull(val2); - continue; - } - assertNotNull(val2); - // not affected - assertEquals(val1,val2); - } - pojo2._obj = null; - assertEquals(pojo2,pojo1); - } - - - public final MethodSetterFactory msf; - - public AbstractMethodSetterFactoryTest(MethodSetterFactory msf) { - this.msf = msf; - } -} diff --git a/core/src/test/java/org/sql2o/reflect/AbstractObjectConstructorFactoryTest.java b/core/src/test/java/org/sql2o/reflect/AbstractObjectConstructorFactoryTest.java deleted file mode 100644 index f16a0ca8..00000000 --- a/core/src/test/java/org/sql2o/reflect/AbstractObjectConstructorFactoryTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.sql2o.reflect; - -import junit.framework.TestCase; -import org.sql2o.reflection.ObjectConstructorFactory; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 10:09 PM - */ -public abstract class AbstractObjectConstructorFactoryTest extends TestCase { - // just a class - public static class POJO1{ - - } - - public final ObjectConstructorFactory ocf; - - public AbstractObjectConstructorFactoryTest(ObjectConstructorFactory ocf) { - this.ocf = ocf; - } - - public void testCreate(){ - Object o = ocf.newConstructor(POJO1.class).newInstance(); - assertNotNull(o); - assertSame(POJO1.class,o.getClass()); - } - - -} diff --git a/core/src/test/java/org/sql2o/reflect/ReadColumnAnnotationTest.java b/core/src/test/java/org/sql2o/reflect/ReadColumnAnnotationTest.java deleted file mode 100644 index df0cb15a..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReadColumnAnnotationTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.sql2o.reflect; - -import com.google.common.collect.ImmutableMap; -import junit.framework.TestCase; -import org.junit.Test; -import org.sql2o.reflection.PojoMetadata; - -import javax.persistence.Column; - -@SuppressWarnings("unused") -public class ReadColumnAnnotationTest extends TestCase { - - @Test - public void testNoAnnotationPojo() { - PojoMetadata metadata = newPojoMetadata(NoAnnotation.class); - assertNotNull(metadata.getPropertySetterIfExists("field1")); - } - - @Test - public void testNoAnnotationSetterPojo() { - PojoMetadata metadata = newPojoMetadata(NoAnnotationSetter.class); - assertNotNull(metadata.getPropertySetterIfExists("field1")); - } - - @Test - public void testOnlyOneAnnotationFieldPojo() { - PojoMetadata metadata = newPojoMetadata(OnlyOneAnnotationField.class); - assertNotNull(metadata.getPropertySetterIfExists("field_1")); - } - - @Test - public void testOneAnnotationFieldPojo() { - PojoMetadata metadata = newPojoMetadata(OneAnnotationField.class); - assertNotNull(metadata.getPropertySetterIfExists("field_1")); - assertNotNull(metadata.getPropertySetterIfExists("field2")); - } - - @Test - public void testAnnotationFieldAndSetterPojo() { - PojoMetadata metadata = newPojoMetadata(AnnotationFieldAndASetter.class); - assertNotNull(metadata.getPropertySetterIfExists("field_1")); - assertNotNull(metadata.getPropertySetterIfExists("field2")); - assertNotNull(metadata.getPropertySetterIfExists("field_3")); - assertNotNull(metadata.getPropertySetterIfExists("field4")); - } - - @Test - public void testUppercaseAnnotationFieldPojo() { - PojoMetadata metadata = newPojoMetadata(UpperCaseAnnotationField.class); - assertNotNull(metadata.getPropertySetterIfExists("field_1")); - } - - private PojoMetadata newPojoMetadata(Class clazz) { - return new PojoMetadata(clazz, false, false, ImmutableMap. of(), true); - } - - private static class NoAnnotation { - private String field1; - } - - private static class NoAnnotationSetter { - private String field1; - - void setField1(String field1) { - this.field1 = field1; - } - } - - private static class OnlyOneAnnotationField { - @Column(name = "field_1") - private String field1; - } - - private static class OneAnnotationField { - @Column(name = "field_1") - private String field1; - private String field2; - } - - private static class AnnotationFieldAndASetter { - @Column(name = "field_1") - private String field1; - private String field2; - private String field3; - private String field4; - - @Column(name = "field_3") - void setField3(String field3) { - this.field3 = field3; - } - - void setField4(String field4) { - this.field4 = field4; - } - } - - private static class UpperCaseAnnotationField { - @Column(name = "FIELD_1") - private String field1; - } - -} diff --git a/core/src/test/java/org/sql2o/reflect/ReflectionConstructorFactoryTest.java b/core/src/test/java/org/sql2o/reflect/ReflectionConstructorFactoryTest.java deleted file mode 100644 index 6769ab8e..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReflectionConstructorFactoryTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sql2o.reflect; - -import org.sql2o.reflection.ReflectionObjectConstructorFactory; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 10:15 PM - */ -public class ReflectionConstructorFactoryTest extends AbstractObjectConstructorFactoryTest { - public ReflectionConstructorFactoryTest() { - super(new ReflectionObjectConstructorFactory()); - } -} diff --git a/core/src/test/java/org/sql2o/reflect/ReflectionFieldGetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/ReflectionFieldGetterFactoryTest.java deleted file mode 100644 index 6ec497a3..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReflectionFieldGetterFactoryTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflect; - -import org.sql2o.reflection.ReflectionFieldGetterFactory; - -/** - * @author mdelapenya - */ -public class ReflectionFieldGetterFactoryTest extends AbstractFieldGetterFactoryTest { - public ReflectionFieldGetterFactoryTest() { - super(new ReflectionFieldGetterFactory()); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/sql2o/reflect/ReflectionFieldSetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/ReflectionFieldSetterFactoryTest.java deleted file mode 100644 index 9d682687..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReflectionFieldSetterFactoryTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sql2o.reflect; - -import org.sql2o.reflection.ReflectionFieldSetterFactory; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 9:44 PM - */ -public class ReflectionFieldSetterFactoryTest extends AbstractFieldSetterFactoryTest { - public ReflectionFieldSetterFactoryTest() { - super(new ReflectionFieldSetterFactory()); - } -} diff --git a/core/src/test/java/org/sql2o/reflect/ReflectionMethodGetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/ReflectionMethodGetterFactoryTest.java deleted file mode 100644 index a373ed94..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReflectionMethodGetterFactoryTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sql2o.reflect; - -import org.sql2o.reflection.ReflectionMethodGetterFactory; - -/** - * @author mdelapenya - */ -public class ReflectionMethodGetterFactoryTest extends AbstractMethodGetterFactoryTest { - public ReflectionMethodGetterFactoryTest() { - super(new ReflectionMethodGetterFactory()); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/sql2o/reflect/ReflectionMethodSetterFactoryTest.java b/core/src/test/java/org/sql2o/reflect/ReflectionMethodSetterFactoryTest.java deleted file mode 100644 index 2c36aaa0..00000000 --- a/core/src/test/java/org/sql2o/reflect/ReflectionMethodSetterFactoryTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sql2o.reflect; - -import org.sql2o.reflection.ReflectionMethodSetterFactory; - -/** - * User: dimzon - * Date: 4/9/14 - * Time: 10:24 PM - */ -public class ReflectionMethodSetterFactoryTest extends AbstractMethodSetterFactoryTest { - public ReflectionMethodSetterFactoryTest() { - super(new ReflectionMethodSetterFactory()); - } -} diff --git a/core/src/test/java/org/sql2o/tools/SnakeToCamelCaseTests.java b/core/src/test/java/org/sql2o/tools/SnakeToCamelCaseTests.java new file mode 100644 index 00000000..fd44eb6f --- /dev/null +++ b/core/src/test/java/org/sql2o/tools/SnakeToCamelCaseTests.java @@ -0,0 +1,27 @@ +package org.sql2o.tools; + +import junit.framework.TestCase; + +public class SnakeToCamelCaseTests extends TestCase { + + public void testBasicConversions() { + assertEquals("myStringVariable", SnakeToCamelCase.convert("my_string_variable")); + assertEquals("string", SnakeToCamelCase.convert("string")); + assertEquals("myReallyLongStringVariableName", SnakeToCamelCase.convert("my_really_long_string_variable_name")); + assertEquals("myString2WithNumbers4", SnakeToCamelCase.convert("my_string2_with_numbers_4")); + assertEquals("myStringWithMixedCase", SnakeToCamelCase.convert("my_string_with_MixED_CaSe")); + } + + public void testNullString() { + assertNull(SnakeToCamelCase.convert(null)); + } + + public void testEmptyStrings() { + assertEquals("", SnakeToCamelCase.convert("")); + assertEquals(" ", SnakeToCamelCase.convert(" ")); + } + public void testWhitespace() { + assertEquals("\t", SnakeToCamelCase.convert("\t")); + assertEquals("\n\n", SnakeToCamelCase.convert("\n\n")); + } +} diff --git a/core/src/test/java/org/sql2o/tools/UnderscoreToCamelCaseTests.java b/core/src/test/java/org/sql2o/tools/UnderscoreToCamelCaseTests.java deleted file mode 100644 index 3675c4f4..00000000 --- a/core/src/test/java/org/sql2o/tools/UnderscoreToCamelCaseTests.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.sql2o.tools; - -import junit.framework.TestCase; - -public class UnderscoreToCamelCaseTests extends TestCase { - - public void testBasicConversions() { - assertEquals("myStringVariable", UnderscoreToCamelCase.convert("my_string_variable")); - assertEquals("string", UnderscoreToCamelCase.convert("string")); - assertEquals("myReallyLongStringVariableName", UnderscoreToCamelCase.convert("my_really_long_string_variable_name")); - assertEquals("myString2WithNumbers4", UnderscoreToCamelCase.convert("my_string2_with_numbers_4")); - assertEquals("myStringWithMixedCase", UnderscoreToCamelCase.convert("my_string_with_MixED_CaSe")); - } - - public void testNullString() { - assertNull(UnderscoreToCamelCase.convert(null)); - } - - public void testEmptyStrings() { - assertEquals("", UnderscoreToCamelCase.convert("")); - assertEquals(" ", UnderscoreToCamelCase.convert(" ")); - } - public void testWhitespace() { - assertEquals("\t", UnderscoreToCamelCase.convert("\t")); - assertEquals("\n\n", UnderscoreToCamelCase.convert("\n\n")); - } -} diff --git a/extensions/db2/pom.xml b/extensions/db2/pom.xml index f477ff80..23c99f81 100644 --- a/extensions/db2/pom.xml +++ b/extensions/db2/pom.xml @@ -18,7 +18,7 @@ org.sql2o.extensions extensions-parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/extensions/oracle-joda-time/pom.xml b/extensions/oracle-joda-time/pom.xml index fe4121a5..b66fc483 100644 --- a/extensions/oracle-joda-time/pom.xml +++ b/extensions/oracle-joda-time/pom.xml @@ -18,7 +18,7 @@ org.sql2o.extensions extensions-parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT @@ -40,10 +40,10 @@ org.sql2o.extensions sql2o-oracle - 1.8.0-SNAPSHOT + ${project.parent.version} test - \ No newline at end of file + diff --git a/extensions/oracle-joda-time/src/test/java/org/sql2o/issues/OracleTest.java b/extensions/oracle-joda-time/src/test/java/org/sql2o/issues/OracleTest.java index 2d15d7f9..fadc018a 100644 --- a/extensions/oracle-joda-time/src/test/java/org/sql2o/issues/OracleTest.java +++ b/extensions/oracle-joda-time/src/test/java/org/sql2o/issues/OracleTest.java @@ -12,24 +12,17 @@ import org.joda.time.DateTime; import org.joda.time.LocalDate; -import org.junit.Ignore; import org.junit.Test; -import org.sql2o.Connection; -import org.sql2o.Query; import org.sql2o.Sql2o; -import org.sql2o.Sql2oException; import org.sql2o.quirks.OracleQuirks; import java.sql.Driver; import java.sql.DriverManager; import java.util.Date; -import java.util.UUID; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; /** * Created with IntelliJ IDEA. diff --git a/extensions/oracle/pom.xml b/extensions/oracle/pom.xml index 8b72a5cf..c37b734a 100644 --- a/extensions/oracle/pom.xml +++ b/extensions/oracle/pom.xml @@ -18,7 +18,7 @@ org.sql2o.extensions extensions-parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT @@ -44,4 +44,4 @@ - \ No newline at end of file + diff --git a/extensions/pom.xml b/extensions/pom.xml index 7b354ebf..d190b8cc 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -18,7 +18,7 @@ org.sql2o sql2o-parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT diff --git a/extensions/postgres/pom.xml b/extensions/postgres/pom.xml index 22e3e35c..c230dc97 100644 --- a/extensions/postgres/pom.xml +++ b/extensions/postgres/pom.xml @@ -18,7 +18,7 @@ org.sql2o.extensions extensions-parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT @@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/extensions/postgres/src/test/java/org/sql2o/extensions/postgres/PostgresTest.java b/extensions/postgres/src/test/java/org/sql2o/extensions/postgres/PostgresTest.java index b5afb7f0..83bc526d 100644 --- a/extensions/postgres/src/test/java/org/sql2o/extensions/postgres/PostgresTest.java +++ b/extensions/postgres/src/test/java/org/sql2o/extensions/postgres/PostgresTest.java @@ -203,6 +203,24 @@ public void testUUID() { } +// @Test +// public void testArray() { +// try (Connection con = sql2o.open()) { +// con.createQuery("create table arraytest (id serial primary key, data text[])").executeUpdate(); +// +// final var data = new String[]{"foo", "bar", "baz"}; +// +// con.createQuery("insert into arraytest(data) values (:data)") +// .addParameter("data", data) +// .executeUpdate(); +// +// var fetchedData = con.createQuery("select data from arraytest") +// .executeScalar(String[].class); +// +// assertThat(fetchedData, is(equalTo(data))); +// } +// } + } diff --git a/pom.xml b/pom.xml index f33589fc..0ad7a63c 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ org.sql2o sql2o-parent Sql2o parent - 1.8.0-SNAPSHOT + 1.9.0-SNAPSHOT Easy database query library @@ -43,6 +43,8 @@ 4.0.2.RELEASE UTF-8 + 1.8 + 1.8 @@ -140,8 +142,8 @@ maven-compiler-plugin 3.1 - 11 - 11 + 17 + 17